màj
|
@ -0,0 +1,224 @@
|
|||
Classes:
|
||||
|
||||
BMPHeader
|
||||
/***************/
|
||||
/* ATTRIBUTS */
|
||||
/***************/
|
||||
|
||||
* CONTENU BRUT PARTIEL (54 premiers bytes)
|
||||
- <binData> header brut (binaire)
|
||||
- <intData> header format liste de (0-255)
|
||||
|
||||
* STRUCTURE DU HEADER
|
||||
- <signature> signature (4D42) par défaut
|
||||
- <fileSize> taille du fichier .bmp (bytes)
|
||||
4 bytes à 0
|
||||
- <offset> début du codage de l'image (bytes)
|
||||
- <infoSize> taille du INFO_HEADER
|
||||
- <width> longueur de l'image (pixels)
|
||||
- <height> hauteur de l'image (pixels)
|
||||
- <plans> nombre de plans (défaut: 1)
|
||||
- <bpp> nombre de bits par pixel (1,4,8,24)
|
||||
- <compType> type de compression (0=none, 1=RLE-8, 2=RLE-4)
|
||||
- <size> taille de l'image avec padding (bytes)
|
||||
- <horiRes> résolution horizontale (pixels)
|
||||
- <vertRes> résolution verticale (pixels)
|
||||
- <colorNb> nombre de couleurs de l'image (ou 0)
|
||||
- <colorINb> nombre de couleurs importantes de l'image (ou 0)
|
||||
|
||||
* VALEURS CALCULEES
|
||||
- <rowSize> taille réelle d'une ligne +padding (bytes)
|
||||
- <padding> taille du padding de fin de ligne (bytes)
|
||||
|
||||
/***************/
|
||||
/* METHODES */
|
||||
/***************/
|
||||
parse(binHeader=""):
|
||||
Définit les attributs à partir de <binData> ou de l'argument <binHeader> si défini
|
||||
|
||||
unparse():
|
||||
Définit <binData>, et <intData> à partir de tout les attributs de structure
|
||||
|
||||
|
||||
info(type=0):
|
||||
Affiche les informations du header au format humain
|
||||
<type> peut valoir 0 (valeur par défaut) pour afficher en nombre, ou 1 pour afficher en hexa
|
||||
|
||||
|
||||
toInt(bytes):
|
||||
Retourne les octets <bytes> sous forme d'entier
|
||||
|
||||
fromInt(value, size):
|
||||
Retourne une chaine de <size> bytes correspondant au binaire de value
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
BMPContent
|
||||
/***************/
|
||||
/* ATTRIBUTS */
|
||||
/***************/
|
||||
|
||||
* CONTENU BRUT
|
||||
- <binData> matrice de pixels brut (binaire)
|
||||
- <intData> matrice de pixels format liste de (0-255)
|
||||
|
||||
* CONTENU EXPLOITABLE
|
||||
- <map> matrice de pixels (instance of RGBPixel)
|
||||
|
||||
|
||||
/***************/
|
||||
/* METHODES */
|
||||
/***************/
|
||||
parse(binContent="", header):
|
||||
Définit les attributs à partir de <binData> ou de l'argument <binContent> si défini ainsi que du header
|
||||
|
||||
unparse(headerHandler=None):
|
||||
Définit <bin> à partir map et définit aussi l'objet <headerHandler> s'il est passé en paramètres
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
BMPFile
|
||||
/***************/
|
||||
/* ATTRIBUTS */
|
||||
/***************/
|
||||
* CONTENU PALETTE (fin du header jusqu'aux pixels)
|
||||
- <binPalette> palette format binaire (header à offset)
|
||||
- <intPalette> palette format list de (0-255)
|
||||
|
||||
* CONTENU BRUT
|
||||
- <binData> contenu complet brut (binaire)
|
||||
- <intData> contenu complet format liste de (0-255)
|
||||
|
||||
* CONTENU STRUCTURE
|
||||
- <header> objet de type <BMPHeader>
|
||||
- <content> objet de type <BMPContent>
|
||||
|
||||
|
||||
/***************/
|
||||
/* METHODES */
|
||||
/***************/
|
||||
parse(binFile=""):
|
||||
Définit les attributs à partir de <binData> ou de l'argument <binFile> si défini
|
||||
|
||||
unparse():
|
||||
Définit <binData> à partir des attributs <BMPHeader> et <BMPContent>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
RGBPixel
|
||||
/***************/
|
||||
/* ATTRIBUTS */
|
||||
/***************/
|
||||
- <r> byte rouge entre 0 et 255
|
||||
- <g> byte vert entre 0 et 255
|
||||
- <b> byte bleu entre 0 et 255
|
||||
|
||||
|
||||
/***************/
|
||||
/* METHODES */
|
||||
/***************/
|
||||
Constructeur(r, g, b):
|
||||
Définit les attributs
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#############
|
||||
## To Do ##
|
||||
#############
|
||||
[x] gestion de la palette (attribut au <parse>) définit par défaut au <unparse>
|
||||
[x] faire que le unparse du content créée le header
|
||||
[ ] prise en charge des formats 1, 4, et 8 bpp
|
||||
|
||||
|
||||
|
||||
#######################################################################
|
||||
####### RECHERCHE DE PRISE EN CHARGE DES DIFFERENTS FORMATS BPP #######
|
||||
#######################################################################
|
||||
PixelColor(r, g, b, bpp=24)
|
||||
<r>, <g>, <b> respectivement les composantes bleue, rouge, verte
|
||||
<bpp> correspond aux bpp
|
||||
|
||||
CAS BPP=1 (noir et blanc)
|
||||
(r+g+b)/3 >= 256 / 2
|
||||
|
||||
1 - blanc
|
||||
2 - noir
|
||||
|
||||
CAS BPP=4 (niveaux de gris)
|
||||
16 * ((r+g+b)/3) / 256
|
||||
|
||||
CAS BPP=8
|
||||
(r+g+b) / 3
|
||||
|
||||
class PixelColor(r, g, b, bpp=24):
|
||||
if bpp not in [1,4,8,24]:
|
||||
self.bpp = 24
|
||||
else:
|
||||
self.bpp = bpp
|
||||
|
||||
|
||||
self.r = r
|
||||
self.g = g
|
||||
self.b = b
|
||||
|
||||
|
||||
# gestion des différents bpp
|
||||
if bpp == 1:
|
||||
self.intColor = int( (r+g+b)/3 > 256/2 )
|
||||
self.binColor = chr( self.intColor )
|
||||
elif bpp == 4:
|
||||
self.intColor = int( 16 * ((r+g+b)/3) / 256 ) )
|
||||
self.binColor = chr( self.intColor )
|
||||
elif bpp == 8:
|
||||
self.intColor = int( (r+g+b) / 3 )
|
||||
self.binColor = chr( self.intColor )
|
||||
else:
|
||||
self.intColor = [r, g, b]
|
||||
self.binColor = chr(b) + chr(g) + chr(r)
|
||||
|
||||
|
||||
|
||||
#######################################################################
|
||||
####### RECHERCHE DE PARSAGE DES PIXELS DE DIFFERENTS BPPS #######
|
||||
#######################################################################
|
||||
ALGO:
|
||||
|
||||
|
||||
firstBit = int(i) + i%1.0; # retourne le rang du premier bit (pas byte)
|
||||
lastBit = firstBit + bpp/8.0
|
||||
|
||||
startByte = int( firstBit ) # ex: pour i =29, on a: 3 octets
|
||||
startBit = int( 8 * (firstBit-startByte) ) # et 5 bits
|
||||
|
||||
stopByte = int( lastBit )
|
||||
stopBit = int( 8 * (lastBit-stopByte) )
|
||||
|
||||
bytes = binData[startByte:stopByte+1]
|
||||
|
||||
intArray = [ ord(x) for x in bytes ]
|
||||
binArray = [ "0" + bin(x)[2:] for x in intArray ]
|
||||
binArray = [ "0"*(8-len(binArray[x])) + binArray[x] for x in range(0, len(binArray)) ]
|
||||
binary = ""
|
||||
for byte in binArray:
|
||||
binary += byte;
|
||||
|
||||
print binArray
|
||||
print "%s to %s => %s" % ( startBit, 8*(stopByte-startByte)+stopBit, binary[startBit:8*(stopByte-startByte) + stopBit] )
|
|
@ -0,0 +1,69 @@
|
|||
Classes:
|
||||
|
||||
|
||||
/******************/
|
||||
/** COLORIZATION **/
|
||||
/******************/
|
||||
Principe: colorer en modifiant les pixels (n&b) dans un ton (teinte) précisée
|
||||
|
||||
restitue la contraste mais recentre la couleur autour de la teinte
|
||||
/************ ALGO **************/
|
||||
i = 50 // incertitude
|
||||
t = RGBPixel(1,2,3) // teinte souhaitée
|
||||
p = RGBPixel(1,2,3) // couleur actuelle
|
||||
|
||||
/************ CODE **************/
|
||||
def colorize(pixel, tint):
|
||||
|
||||
|
||||
|
||||
|
||||
/*****************/
|
||||
/** SHAPIZATION **/
|
||||
/*****************/
|
||||
Principe: récupérer une forme par récurrence
|
||||
|
||||
Ajouter les 8 bits périphériques du pixel courant s'il existe et s'il a des couleurs pas trop éloignées des précédentes
|
||||
/************ ALGO **************/
|
||||
|
||||
/************ CODE **************/
|
||||
def getShape(self, coords, pixelMap, pixelList ): # return 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]
|
||||
|
||||
newCoords = [x, y]
|
||||
|
||||
|
||||
# si le pixel existe (pas de dépassement de la pixelMap)
|
||||
if x<width and x>=0 and y<height and y>=0:
|
||||
|
||||
already = False;
|
||||
for i in range(0, len(pixelList)):
|
||||
if pixelList[i] == pixelMap[y][x]:
|
||||
already = True;
|
||||
break
|
||||
|
||||
# si le pixel n'est pas déjà dans le tableau
|
||||
if not already:
|
||||
|
||||
pixelMap[y][x].setRGB(255,0,0); # debug, tout rouge
|
||||
|
||||
pixelList.append( pixelMap[y][x] ) # ajout au tableau
|
||||
|
||||
self.getShape(newCoords+[x-1, y+1], pixelMap, pixelList) # 1
|
||||
self.getShape(newCoords+[x, y+1], pixelMap, pixelList) # 2
|
||||
self.getShape(newCoords+[x+1, y+1], pixelMap, pixelList) # 3
|
||||
|
||||
self.getShape(newCoords+[x-1, y], pixelMap, pixelList) # 4
|
||||
# current pixel
|
||||
self.getShape(newCoords+[x+1, y], pixelMap, pixelList) # 6
|
||||
|
||||
self.getShape(newCoords+[x-1, y-1], pixelMap, pixelList) # 7
|
||||
self.getShape(newCoords+[x, y-1], pixelMap, pixelList) # 8
|
||||
self.getShape(newCoords+[x+1, y-1], pixelMap, pixelList) # 9
|
|
@ -0,0 +1,65 @@
|
|||
# ~*~ encoding: utf-8 ~*~ #
|
||||
###########################
|
||||
# TRAITEMENT D'IMAGES #
|
||||
###########################
|
||||
|
||||
# classes
|
||||
from BMPFile import *
|
||||
from Noise import *
|
||||
import random
|
||||
import sys
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
def testFileIntegrity():
|
||||
# lecture du fichier
|
||||
with open( sys.argv[1] ) as file:
|
||||
binFile = file.read()
|
||||
|
||||
# Instanciation du BMPFile
|
||||
img = BMPFile()
|
||||
# Instanciation du NoiseObject
|
||||
noise = Noise();
|
||||
|
||||
# Parsing
|
||||
img.parse( binFile );
|
||||
|
||||
noise.SaltAndPepper_set(10, img.content.map)
|
||||
|
||||
|
||||
# Unparsing
|
||||
img.unparse(newBpp=24)
|
||||
|
||||
print img.binData
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
def testManualCreation():
|
||||
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 img.binData
|
||||
|
||||
# MAIN
|
||||
#testManualCreation()
|
||||
testFileIntegrity()
|
After Width: | Height: | Size: 768 KiB |
After Width: | Height: | Size: 768 KiB |
|
@ -68,6 +68,7 @@ print "| 43) %s |" % exactLength("Prewitt", 21, -1)
|
|||
print "| 44) %s |" % exactLength("Sobel", 21, -1)
|
||||
print "| 45) %s |" % exactLength("Convolution", 21, -1)
|
||||
print "| 46) %s |" % exactLength("bichrome", 21, -1)
|
||||
print "| 47) %s |" % exactLength("Passe Haut", 21, -1)
|
||||
print "+---------------------------+"
|
||||
print
|
||||
while True:
|
||||
|
@ -207,6 +208,9 @@ elif action == 45:
|
|||
elif action == 46:
|
||||
print startStr
|
||||
testBichrome() # teste le passage au bichromatique
|
||||
elif action == 47:
|
||||
print startStr
|
||||
testHighPass() # teste le filtre passe haut
|
||||
|
||||
else:
|
||||
print "Wrong choice"
|
||||
|
|
After Width: | Height: | Size: 352 KiB |
|
@ -1453,3 +1453,48 @@ def testBichrome():
|
|||
|
||||
|
||||
|
||||
# teste le filtre de passe haut sur d'une image #
|
||||
#################################################
|
||||
# @sysarg 1 le fichier d'origine
|
||||
# @stsarg 2 le fichier de sortie (filtré)
|
||||
#
|
||||
# @history
|
||||
# Parse le fichier d'origine
|
||||
# Applique le filtre
|
||||
# Unparse l'image et l'enregistre dans le fichier de sortie
|
||||
def testHighPass():
|
||||
t = Timer();
|
||||
|
||||
|
||||
# lecture du fichier
|
||||
print "| Reading Image |",; t.reset();
|
||||
with open( sys.argv[1] ) as file:
|
||||
binFile = file.read()
|
||||
print "%s |" % (t.get())
|
||||
|
||||
|
||||
img = BMPFile(); # Instanciation du BMPFile
|
||||
|
||||
|
||||
# Parsing
|
||||
print "| Parsing file |",; t.reset();
|
||||
img.parse( binFile );
|
||||
print "%s |" % (t.get())
|
||||
|
||||
|
||||
print "| Application du filtre |",; t.reset();
|
||||
img.content.map = FX.Filter.HighPass(img.content.map);
|
||||
print "%s |" % (t.get())
|
||||
|
||||
# Unparsing
|
||||
print "| Unparsing file |",; t.reset();
|
||||
img.unparse()
|
||||
print "%s |" % (t.get())
|
||||
|
||||
# image to stdout
|
||||
print "| Writing file |",; t.reset();
|
||||
img.write( sys.argv[2] )
|
||||
print "%s |" % (t.get())
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -19,13 +19,13 @@ class Filter:
|
|||
# Celà revient à effectuer un produit de convolution avec le noyau de conv. suivant :
|
||||
#
|
||||
# 1 1 1
|
||||
# 1 0 1
|
||||
# 1 1 1
|
||||
# 1 1 1
|
||||
#
|
||||
def averageFilter(self, pixelMap):
|
||||
return self.Convolution(pixelMap, kernel=[
|
||||
[1, 1, 1],
|
||||
[1, 0, 1],
|
||||
[1, 1, 1],
|
||||
[1, 1, 1]
|
||||
] );
|
||||
|
||||
|
@ -84,6 +84,25 @@ class Filter:
|
|||
] );
|
||||
|
||||
|
||||
# Applique un filtre passe-haut à l'image de base vers l'image de sortie #
|
||||
##########################################################################
|
||||
# @param pixelMap Matrice de pixel à traiter (modifier)
|
||||
#
|
||||
#
|
||||
# Celà revient à effectuer un produit de convolution avec le noyau de conv. suivant :
|
||||
#
|
||||
# -1 0 1
|
||||
# -2 0 2
|
||||
# -1 0 1
|
||||
#
|
||||
def HighPass(self, pixelMap):
|
||||
return self.Convolution(pixelMap, kernel=[
|
||||
[ 0, -1, 0],
|
||||
[-1, 5, -1],
|
||||
[ 0, -1, 0]
|
||||
] );
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
After Width: | Height: | Size: 32 KiB |
After Width: | Height: | Size: 16 KiB |
After Width: | Height: | Size: 14 KiB |
After Width: | Height: | Size: 17 KiB |
|
@ -548,15 +548,32 @@
|
|||
On effectue ensuite la soustraction matricielle afin de mettre les contours en valeur\\
|
||||
|
||||
\indent \emph{Méthode 2 - indépendentisation de contour}\\
|
||||
L'image est lissée avec un filtre moyen. Nous effectuons un produit de convolution (noté \begin{math}\otimes\end{math}) avec l'image \emph{I} et le noyau tel que défini :
|
||||
\begin{align*}
|
||||
I_{lisse} = I\ \otimes\ \frac{1}{8} \begin{pmatrix}
|
||||
1 & 1 & 1\\
|
||||
1 & 0 & 1\\
|
||||
1 & 1 & 1
|
||||
\end{pmatrix}
|
||||
\end{align*}
|
||||
On effectue ensuite la soustraction matricielle afin de mettre les contours en valeur
|
||||
Un algorithme lance sur chaque pixel de l'image un "envahisseur", c'est-à-dire un algorithme qui référencie chaque pixel considéré dans la même forme que le pixel de départ. par exemple, on obtient le résultat ci-dessous en essayant de récupérer les formes noires uniquement :
|
||||
% indépendentisation de contour
|
||||
\begin{figure}[!ht]
|
||||
\centering
|
||||
\begin{minipage}[t]{3.5cm}
|
||||
\centering
|
||||
\includegraphics[width=3.5cm]{Vectorization/shape.jpg}
|
||||
Image originale
|
||||
\end{minipage}
|
||||
\begin{minipage}[t]{3.5cm}
|
||||
\centering
|
||||
\includegraphics[width=3.5cm]{Vectorization/shapeDetection1.jpg}
|
||||
Détection sur forme 1
|
||||
\end{minipage}
|
||||
\begin{minipage}[t]{3.5cm}
|
||||
\centering
|
||||
\includegraphics[width=3.5cm]{Vectorization/shapeDetection2.jpg}
|
||||
Détection sur forme 2
|
||||
\end{minipage}
|
||||
\begin{minipage}[t]{3.5cm}
|
||||
\centering
|
||||
\includegraphics[width=3.5cm]{Vectorization/shapeDetection3.jpg}
|
||||
Détection sur forme 3
|
||||
\end{minipage}
|
||||
\end{figure}\\
|
||||
Les résultats sont corrects mais le traitement devient vite très long, le temps d'éxécution moyen pour ces résultats est de 20 secondes. Nous avons donc décidé de créer un nouvel algorithme qui lui récupérerait uniquement les contours.
|
||||
|
||||
|
||||
\newpage
|
||||
|
|