IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Traitement d'images Discussion :

Détection de contour précis dans une image propre


Sujet :

Traitement d'images

  1. #1
    Membre éprouvé Avatar de electroremy
    Homme Profil pro
    Ingénieur sécurité
    Inscrit en
    Juin 2007
    Messages
    934
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Doubs (Franche Comté)

    Informations professionnelles :
    Activité : Ingénieur sécurité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2007
    Messages : 934
    Points : 1 274
    Points
    1 274
    Par défaut Détection de contour précis dans une image propre
    Bonsoir,

    le titre de mon post peut surprendre :-)

    en bref :

    - j'ai une image très propre, c'est à dire un noir et blanc avec une bonne résolution (ou niveau de gris : noir et blanc avec antialiasing) générée par un logiciel tel que CAO, traitement de texte, logiciel de dessin
    - à partir de cette image, qui contient des formes en noir et blanc (formes qui peuvent êtres des textes ou des formes géométriques) je cherche à déterminer les contours de ces formes
    - par contour j'entends une liste de point (x,y) assez précise, chaque point étant relié par un seguement de droite pour former un contour fermé dans le sens horaire, épousant au mieux la forme dans l'image

    Depuis 15 jours je fais des calculs et des recherches... mais je ne trouve pas de solution adapté à mon problème. Dans le domaine du traitement d'image, je ne trouve que des solutions adaptées à des images "sales" (comme des photos par exemple) et qui ne donnent comme résultat que d'autres images (ce qui est inutile dans mon cas)...

    Pourquoi je veux faire cela ? En fait, j'ai créé quelques logiciels de CAO qui sortent des images pour impression (par ex pour réalisation de circuits imprimés par méthode photographique)

    Je souhaite pourvoir usiner ces formes dessinées, et les calculs à faire pour équiper chaque logiciel de la fonction usinage sont extrêmement complexes...

    Autre aspect des choses : avec une machine, un bug = une casse de matériel !

    Hors, la génération d'image de mes programmes est fiable, et j'ai expérimenté une solution simple : la possibilité d'usiner une image en niveau de gris, la valeur de gris correspondant à la hauteur Z... mais le soucis c'est que la résolution est décevante.... Car l'usinage se fait avec des passes "en balayage" (méthode bourrin) au lieu de chercher à suivre les courbes de niveau dans l'image

    Donc je cherche à créer un logiciel qui permet d'usiner proprement une image simple (fortement contrastée), la solution étant que les mouvement de l'outil suivent les contours

    Merci

    A+
    Quand deux personnes échangent un euro, chacun repart avec un euro.
    Quand deux personnes échangent une idée, chacun repart avec deux idées.

  2. #2
    Membre éprouvé Avatar de electroremy
    Homme Profil pro
    Ingénieur sécurité
    Inscrit en
    Juin 2007
    Messages
    934
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Doubs (Franche Comté)

    Informations professionnelles :
    Activité : Ingénieur sécurité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2007
    Messages : 934
    Points : 1 274
    Points
    1 274
    Par défaut
    J'ai trouvé quelque chose d'intéressant :

    http://potrace.sourceforge.net/

    Ce code fonctionne uniquement avec des bitmaps en noir et blanc. Il permet d'obtenir une image vectorielle (donc ce que je cherche)

    Cerise sur le gâteau : le code existe en API et l'algorithme est expliqué en détail

    Je vais essayer de l'adapter pour mon besoin...

    si vous avez d'autres pistes je suis preneur

    A+
    Quand deux personnes échangent un euro, chacun repart avec un euro.
    Quand deux personnes échangent une idée, chacun repart avec deux idées.

  3. #3
    Modérateur
    Avatar de ToTo13
    Homme Profil pro
    Chercheur en informatique
    Inscrit en
    Janvier 2006
    Messages
    5 793
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : Etats-Unis

    Informations professionnelles :
    Activité : Chercheur en informatique
    Secteur : Santé

    Informations forums :
    Inscription : Janvier 2006
    Messages : 5 793
    Points : 9 860
    Points
    9 860
    Par défaut
    Et si tu nous montrais une de ces "images propres" à segmenter !
    Consignes aux jeunes padawans : une image vaut 1000 mots !
    - Dans ton message respecter tu dois : les règles de rédaction et du forum, prévisualiser, relire et corriger TOUTES les FAUTES (frappes, sms, d'aurteaugrafe, mettre les ACCENTS et les BALISES) => ECRIRE clairement et en Français tu DOIS.
    - Le côté obscur je sens dans le MP => Tous tes MPs je détruirai et la réponse tu n'auras si en privé tu veux que je t'enseigne.(Lis donc ceci)
    - ton poste tu dois marquer quand la bonne réponse tu as obtenu.

  4. #4
    Membre éprouvé Avatar de electroremy
    Homme Profil pro
    Ingénieur sécurité
    Inscrit en
    Juin 2007
    Messages
    934
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Doubs (Franche Comté)

    Informations professionnelles :
    Activité : Ingénieur sécurité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2007
    Messages : 934
    Points : 1 274
    Points
    1 274
    Par défaut
    Citation Envoyé par ToTo13 Voir le message
    Et si tu nous montrais une de ces "images propres" à segmenter !
    Effectivement, avec un exemple sous les yeux c'est plus parlant :-)

    Nom : 14_typ_coupure.gif
Affichages : 3866
Taille : 36,4 Ko

    A+
    Quand deux personnes échangent un euro, chacun repart avec un euro.
    Quand deux personnes échangent une idée, chacun repart avec deux idées.

  5. #5
    Modérateur
    Avatar de ToTo13
    Homme Profil pro
    Chercheur en informatique
    Inscrit en
    Janvier 2006
    Messages
    5 793
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : Etats-Unis

    Informations professionnelles :
    Activité : Chercheur en informatique
    Secteur : Santé

    Informations forums :
    Inscription : Janvier 2006
    Messages : 5 793
    Points : 9 860
    Points
    9 860
    Par défaut
    Effectivement l'image est parfaite, tu n'as besoin d'aucun pré-traitement.
    Donc dans ton cas c'est très simple :
    - étiquetage des composantes connexes pour isoler les formes.
    - parcours de l'image et pour chaque pixel il faut tester s'il a des voisins noir et blanc. Si c'est le cas, alors il appartient au contour de la forme.
    Consignes aux jeunes padawans : une image vaut 1000 mots !
    - Dans ton message respecter tu dois : les règles de rédaction et du forum, prévisualiser, relire et corriger TOUTES les FAUTES (frappes, sms, d'aurteaugrafe, mettre les ACCENTS et les BALISES) => ECRIRE clairement et en Français tu DOIS.
    - Le côté obscur je sens dans le MP => Tous tes MPs je détruirai et la réponse tu n'auras si en privé tu veux que je t'enseigne.(Lis donc ceci)
    - ton poste tu dois marquer quand la bonne réponse tu as obtenu.

  6. #6
    Membre éprouvé Avatar de electroremy
    Homme Profil pro
    Ingénieur sécurité
    Inscrit en
    Juin 2007
    Messages
    934
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Doubs (Franche Comté)

    Informations professionnelles :
    Activité : Ingénieur sécurité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2007
    Messages : 934
    Points : 1 274
    Points
    1 274
    Par défaut
    Citation Envoyé par ToTo13 Voir le message
    Effectivement l'image est parfaite, tu n'as besoin d'aucun pré-traitement.
    Donc dans ton cas c'est très simple :
    - étiquetage des composantes connexes pour isoler les formes.
    - parcours de l'image et pour chaque pixel il faut tester s'il a des voisins noir et blanc. Si c'est le cas, alors il appartient au contour de la forme.
    Tu pourrais me donner plus de détail sur l'algorithme que tu me suggère ?

    Je voulais tester la méthode de PoTrace aujourd'hui mais j'ai un soucis avec VB.NET qui m'empêche de travailler (http://www.developpez.net/forums/d14...l/#post7784219)

    Donc du coup j'ai avancé sur un autre logiciel, CiDess... en VB5 :-P (CiDess est le programme qui a servit à créer le circuit imprimé montré en exemple). Je suis en train d'essayer de programmer l'usinage directement à partir de CiDess, mais je sais déjà que pour les textes je n'ai pas de solution dans l'immédiat (certains circuits imprimés comportent des textes, cette fonctionnalité est très appréciée des utilisateurs)

    Concrètement, pour CiDess, je dois passer du dessin à l'usinage :
    - en dessin, je dessine des formes noires (morceaux de pistes, pastilles) qui se superposent, cela n'est pas gênant quand on créé une image
    - mais en usinage, où il faut détourer ce qui est noir (donc l'outil va suivre les contours), il va falloir que je fusionne proprement toutes les formes qui se chevauchent pour obtenir une collection de contours fermés propres qui ne se chevauchent pas, car sinon, l'usinage va couper les pistes à chaque connexion et autour de chaque pastille.

    (NB : Gros avantage pour moi : dans CiDess je peux gérer les perçages à part, donc mes formes noires n'ont aucun contour "interne" en blanc.)

    Ce calcul de fusion est faisable sans trop de difficultés pour les formes telles que morceaux de pistes, pastilles... par contre pour les textes... pour y parvenir je devrait interpréter moi-même les polices TTF, grosse galère. J'ai déjà eu de nombreux problèmes à l'époque du développement de CiDess pour simplement avoir une impression conforme à l'écran à cause de problèmes de mises à l'échelle et de déformations. (les textes étaient soit trop gros, soit trop petits, cela créait des courts-circuits...)

    Donc voilà pourquoi j'essaye de créer du G-CODE à partir d'une image... avec une détection de contour propre, car les logiciels d'impression d'image de type "heightmap" sont trop lents et ont une résolution médiocre.

    D'autre part, ce programme d'usinage propre à partir d'une image permettrait de graver facilement des faces avant, des plaques de boite aux lettres, ect... directement à partir du traitement de texte ou du logiciel de dessin qui a servit à faire les étiquettes... car oui bien sûr, des logiciels permettant d'usiner du texte existent, mais il faut refaire tous les fichiers dans ces logiciels... impossible de convertir en trois clic de souris une étiquette faite avec word ou photoshop en fichier XXX pour logiciel d'usinage

    A+
    Quand deux personnes échangent un euro, chacun repart avec un euro.
    Quand deux personnes échangent une idée, chacun repart avec deux idées.

  7. #7
    Modérateur
    Avatar de ToTo13
    Homme Profil pro
    Chercheur en informatique
    Inscrit en
    Janvier 2006
    Messages
    5 793
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : Etats-Unis

    Informations professionnelles :
    Activité : Chercheur en informatique
    Secteur : Santé

    Informations forums :
    Inscription : Janvier 2006
    Messages : 5 793
    Points : 9 860
    Points
    9 860
    Par défaut
    Doucement, une chose à la fois.
    Pour l'instant on en est là :
    Citation Envoyé par electroremy Voir le message
    - à partir de cette image, qui contient des formes en noir et blanc (formes qui peuvent êtres des textes ou des formes géométriques) je cherche à déterminer les contours de ces formes
    - 1 - Les formes sont noires, il faut tout d'abord les isoler pour savoir combien il y en a et pour ne pas mélanger les contours.
    Donc on fait un étiquetage des composantes connexes. Voir dans ce forum ce que c'est si tu ne connais pas ; on a détaillé le principe très souvent et tu as du code java (basique, presque du C) dans le rubrique Contribuez.

    - 2 - tu parcours l'image et tu testes chaque pixel noir pour savoir s'il appartient à un bord/frontière/contour de forme.
    A ce stade, tu sais alors quels sont les points de contour et si tu fais le lien avec l'étape 1, tu connais également à quelle forme ils appartiennent.

    - 3 - pour chaque ensemble de point de contour, tu les ordonnes dans le sens que tu souhaites (déjà traité dans le forum).
    Consignes aux jeunes padawans : une image vaut 1000 mots !
    - Dans ton message respecter tu dois : les règles de rédaction et du forum, prévisualiser, relire et corriger TOUTES les FAUTES (frappes, sms, d'aurteaugrafe, mettre les ACCENTS et les BALISES) => ECRIRE clairement et en Français tu DOIS.
    - Le côté obscur je sens dans le MP => Tous tes MPs je détruirai et la réponse tu n'auras si en privé tu veux que je t'enseigne.(Lis donc ceci)
    - ton poste tu dois marquer quand la bonne réponse tu as obtenu.

  8. #8
    Membre éprouvé Avatar de electroremy
    Homme Profil pro
    Ingénieur sécurité
    Inscrit en
    Juin 2007
    Messages
    934
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Doubs (Franche Comté)

    Informations professionnelles :
    Activité : Ingénieur sécurité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2007
    Messages : 934
    Points : 1 274
    Points
    1 274
    Par défaut
    OK merci pour ton aide J'ai trouvé ton programme "Union-Find" qui a l'air assez intéressant

    En fait, la 1ière partie de l'algorithme POTRACE fait directement la même chose que tes étapes 1, 2 et 3 (voir http://potrace.sourceforge.net/potrace.pdf)

    La suite de POTRACE fait un lissage (c'est du luxe !)

    Pour l'instant je ne fait que de l'algorithme sur des feuilles de papiers, faute de pouvoir manipuler un bitmap monochrome avec VB.NET

    Je ne dis pas que ce n'est pas intéressant, au contraire, mais c'est très frustrant de ne pas pouvoir générer un exécutable et de le voir fonctionner.

    Je vais donc essayer de lire directement un fichier BMP monochrome (généré par un programme tiers) en VB dans un tableau d'octets, sans passer par la classe bitmap et marshal de VB.NET. D'ailleurs ça vaux mieux - vu que mon programme n'a pas besoin d'afficher l'image, l'utilisation de la classe bitmap est une perte de temps de calcul et aussi une perte de mémoire vive

    A+
    Quand deux personnes échangent un euro, chacun repart avec un euro.
    Quand deux personnes échangent une idée, chacun repart avec deux idées.

  9. #9
    Modérateur
    Avatar de ToTo13
    Homme Profil pro
    Chercheur en informatique
    Inscrit en
    Janvier 2006
    Messages
    5 793
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : Etats-Unis

    Informations professionnelles :
    Activité : Chercheur en informatique
    Secteur : Santé

    Informations forums :
    Inscription : Janvier 2006
    Messages : 5 793
    Points : 9 860
    Points
    9 860
    Par défaut
    ... pourquoi lisser un contour aussi net ???

    Tu peux générer un tableau (représentant une image) et travailler dessus.
    Consignes aux jeunes padawans : une image vaut 1000 mots !
    - Dans ton message respecter tu dois : les règles de rédaction et du forum, prévisualiser, relire et corriger TOUTES les FAUTES (frappes, sms, d'aurteaugrafe, mettre les ACCENTS et les BALISES) => ECRIRE clairement et en Français tu DOIS.
    - Le côté obscur je sens dans le MP => Tous tes MPs je détruirai et la réponse tu n'auras si en privé tu veux que je t'enseigne.(Lis donc ceci)
    - ton poste tu dois marquer quand la bonne réponse tu as obtenu.

  10. #10
    Membre éprouvé Avatar de electroremy
    Homme Profil pro
    Ingénieur sécurité
    Inscrit en
    Juin 2007
    Messages
    934
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Doubs (Franche Comté)

    Informations professionnelles :
    Activité : Ingénieur sécurité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2007
    Messages : 934
    Points : 1 274
    Points
    1 274
    Par défaut
    Citation Envoyé par ToTo13 Voir le message
    Tu peux générer un tableau (représentant une image) et travailler dessus.
    => OUI ! D'ailleurs c'est pour cela que je souhaite lire directement un fichier bmp en binaire

    Citation Envoyé par ToTo13 Voir le message
    pourquoi lisser un contour aussi net ???
    => il faut lisser au minimum au niveau du pixel. Avec la 1ière étape de PoTrace, le contour est "pixelisé" en marches d'escalier donc avec des crans correspondant aux pixels (du moins lorsque les trajectoires ne sont pas verticales ou horizontale). Un léger lissage permet d'avoir des points alignés suivant une droite et non un escalier

    A noter que PoTrace travaille avec les coordonnées des coins des pixels (en fait décalage d'un demi pixel sur X et Y) et non en centre pixel. Compte tenu de l'algorithme utilisé c'est logique

    A+
    Quand deux personnes échangent un euro, chacun repart avec un euro.
    Quand deux personnes échangent une idée, chacun repart avec deux idées.

  11. #11
    Membre éprouvé Avatar de electroremy
    Homme Profil pro
    Ingénieur sécurité
    Inscrit en
    Juin 2007
    Messages
    934
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Doubs (Franche Comté)

    Informations professionnelles :
    Activité : Ingénieur sécurité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2007
    Messages : 934
    Points : 1 274
    Points
    1 274
    Par défaut
    Bonjour,

    c'est cool j'ai bien avancé - le traitement d'image est fait sans DLL ni fonctions graphiques, en travaillant dans un tableau de byte

    Voici d'abord quelques explications :

    Nom : Explications.gif
Affichages : 3561
Taille : 10,4 Ko

    Les carrés sont les pixels de l’image. Le centre du pixel en bas à gauche a pour coordonnées (0,0)

    Les carrés blancs sont les pixels blancs, les carrés orange sont les pixels noirs de l’image

    La méthode de détection de contour est celle de PoTrace. Les points et les flèches (vecteurs) en rouge représentent un contour. Les coordonnées des points du contour ne correspondent pas aux centres des pixels, mais à leurs coins. Il y a un décalage d’un demi-pixel entre les deux systèmes de coordonnées.

    Un contour est définit par la liste des points dans le bon ordre, dans le sens des flèches (sens antihoraire) ; les pixels noirs à l’intérieur du contour sont donc toujours à gauche des flèches.

    Chaque point d’un contour est définit par ses coordonnées X et Y, et par la direction de la flèche qui pointe sur lui (c’est-à-dire la flèche qui le relie au point précédent). Les contours sont fermés, le point précédent du premier point est le dernier point de la liste.

    La direction est stockée sous forme de nombre entier : 0 de gauche à droite ; 1 de bas en haut ; 2 de droite à gauche ; 3 de haut en bas.

    L’image est parcourue jusqu’à trouver un pixel noir. Le contour est alors « suivit » point par point, jusqu’à ce qu’il soit fermé. Ensuite, la couleur des pixels à l’intérieur du contour est inversée (noir devient blanc et blanc devient noir). L’image est parcourue de nouveaux, jusqu’à ce qu’il n’y ai plus de pixel noir.

    Cette façon de procéder fait que les contours situés à l’intérieur d’autres contours sont détectés de la même façon. Un calcul ultérieur est nécessaire pour savoir de quelle façon les contours sont imbriqués.

    Pour peindre (ou inverser les pixels) de l’intérieur d’un contour, on fait d’abord la liste de tous les vecteurs vers le haut, et la liste de tous les vecteurs vers le bas. Ensuite, on forme des couples de vecteurs qui divisent l’intérieur du contour en segments : pour chaque vecteur vers le haut, on cherche sur la même ligne le vecteur vers le bas à gauche le plus proche. Ensuite, pour chaque couple, on peint le segment de droite situé entre les deux vecteurs. Chaque pixel n’est lu et écrit qu’une seule fois, c’est une méthode de flood fill très efficace.

    Voici le code complet :

    Code VB.NET : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
    230
    231
    232
    233
    234
    235
    236
    237
    238
    239
    240
    241
    242
    243
    244
    245
    246
    247
    248
    249
    250
    251
    252
    253
    254
    255
    256
    257
    258
    259
    260
    261
    262
    263
    264
    265
    266
    267
    268
    269
    270
    271
    272
    273
    274
    275
    276
    277
    278
    279
    280
    281
    282
    283
    284
    285
    286
    287
    288
    289
    290
    291
    292
    293
    294
    295
    296
    297
    298
    299
    300
    301
    302
    303
    304
    305
    306
    307
    308
    309
    310
    311
    312
    313
    314
    315
    316
    317
    318
    319
    320
    321
    322
    323
    324
    325
    326
    327
    328
    329
    330
    331
    332
    333
    334
    335
    336
    337
    338
    339
    340
    341
    342
    343
    344
    345
    346
    347
    348
    349
    350
    351
    352
    353
    354
    355
    356
    357
    358
    359
    360
    361
    362
    363
    364
    365
    366
    367
    368
    369
    370
    371
    372
    373
    374
    375
    376
    377
    378
    379
    380
    381
    382
    383
    384
    385
    386
    387
    388
    389
    390
    391
    392
    393
    394
    395
    396
    397
    398
    399
    400
    401
    402
    403
    404
    405
    406
    407
    408
    409
    410
    411
    412
    413
    414
    415
    416
    417
    418
    419
    420
    421
    422
    423
    424
    425
    426
    427
    428
    429
    430
    431
    432
    433
    434
    435
    436
    437
    438
    439
    440
    441
    442
    443
    444
    445
    446
    447
    448
    449
    450
    451
    452
    453
    454
    455
    456
    457
    458
    459
    460
    461
    462
    463
    464
    465
    466
    467
    468
    469
    470
    471
    472
    473
    474
    475
    476
    477
    478
    479
    480
    481
    482
    483
    484
    485
    486
    487
    488
    489
    490
    491
    492
    493
    494
    495
    496
    497
    498
    499
    500
    501
    502
    503
    504
    505
    506
    507
    508
    509
    510
    511
    512
    513
    514
    515
    516
    517
    518
    519
    520
    521
    522
    523
    524
    525
    526
    527
    528
    529
    530
    531
    532
    533
    534
    535
    536
    537
    538
    539
    540
    541
    542
    543
    544
    545
    546
    547
    548
    549
    550
    551
    552
    553
    554
    555
    556
    557
    558
    559
    560
    561
    562
    563
    564
    565
    566
    567
    568
    569
    570
    571
    572
    573
    574
    575
    576
    577
    578
    579
    580
    581
    582
    583
    584
    585
    586
    587
    588
    589
    590
    591
    592
    593
    594
    595
    596
    597
    598
    599
    600
    601
    602
    603
    604
    605
    606
    607
    608
    609
    610
    611
    612
    613
    614
    615
    616
    617
    618
    619
    620
    621
    622
    623
    624
    625
    626
    627
    628
    629
    630
    631
    632
    633
    634
    635
    636
    637
    638
    639
    640
    641
    642
    643
    644
    645
    646
    647
    648
    649
    650
    651
    652
    653
    654
    655
    656
    657
    658
    659
    660
    661
    662
    663
    664
    665
    666
    667
    668
    669
    670
    671
    672
    673
    674
    675
    676
    677
    678
    679
    680
    681
    682
    683
    684
    685
    686
    687
    688
    689
    690
    691
    692
    693
    694
    695
    696
    697
    698
    699
    700
    701
    702
    703
    704
    705
    706
    707
    708
    709
    710
    711
    712
    713
    714
    715
    716
    717
    718
    719
    720
    721
    722
    723
    724
    725
    726
    727
    728
    729
    730
    731
    732
    733
    734
    735
    736
    737
    738
    739
    740
    741
    742
    743
    744
    745
    746
    747
    748
    749
    750
    751
    752
    753
    754
    755
    756
    757
    758
    759
    760
    761
    762
    763
    764
    765
    766
    767
    768
    769
    770
    771
    772
    773
    774
    775
    776
    777
    778
    779
    780
    781
    782
    783
    784
    785
    786
    787
    788
    789
    790
    791
    792
    793
    794
    795
    796
    797
    798
    799
    800
    801
    802
    803
    804
    805
    806
    807
    808
    809
    810
    811
    812
    813
    814
    815
    816
    817
    818
    819
    820
    821
    822
    823
    824
    825
    826
    827
    828
    829
    830
    831
    832
    833
    834
    835
    836
    837
    838
    839
    840
    841
    842
    843
    844
    845
    846
    847
    848
    849
    850
    851
    852
    853
    854
    855
    856
    857
    858
    859
    860
    861
    862
    863
    864
    865
    866
    867
    868
    869
    870
    871
    872
    873
    874
    875
    876
    877
    878
    879
    880
    881
    882
    883
    884
    885
    886
    887
    888
    889
    890
    891
    892
    893
    894
    895
    896
    897
    898
    899
    900
    901
    902
    903
    904
    905
    906
    907
    908
    909
    910
    911
    912
    913
    914
    915
    916
    917
    918
    919
    920
    921
    922
    923
    924
    925
    926
    927
    928
    929
    930
    931
    932
    933
    934
    935
    936
    937
    938
    939
    940
    941
    942
    943
    944
    945
    946
    947
    948
    949
    950
    951
    952
    953
    954
    955
    956
    957
    958
    959
    960
    961
    962
    963
    964
    965
    966
    967
    968
    969
    970
    971
    972
    973
    974
    975
    976
    977
    978
    979
    980
    981
    982
    983
    984
    985
    986
    987
    988
    989
    990
    991
    992
    993
    994
    995
    996
    997
    998
    999
    1000
    1001
    1002
    1003
    1004
    1005
    1006
    1007
    1008
    1009
    1010
    1011
    1012
    1013
    1014
    1015
    1016
    1017
    1018
    1019
    1020
    1021
    1022
    1023
    1024
    1025
    1026
    1027
    1028
    1029
    1030
    1031
    1032
    1033
    1034
    1035
    1036
    1037
    1038
    1039
    1040
    1041
    1042
    1043
    1044
    1045
    1046
    1047
    1048
    1049
    1050
    1051
    1052
    1053
    1054
    1055
    1056
    1057
    1058
    Imports System
    Imports System.IO
    Imports System.Security.Permissions
     
    Public Class Form1
        Private Sub Button4_Click(sender As System.Object, e As System.EventArgs) Handles Button4.Click
            Dim bm As BMP1BIT
            bm = New BMP1BIT
     
            Call bm.DemarrerMesureTemps()
            Call bm.Lire(My.Application.Info.DirectoryPath + "\ImageALire_GRIS.BMP")
            Call bm.FinMesureTemps("Lecture")
     
            Call bm.DemarrerMesureTemps()
            Call bm.Ecrire(My.Application.Info.DirectoryPath + "\Image1.BMP")
            Call bm.FinMesureTemps("Lecture")
     
            Call bm.DemarrerMesureTemps()
            Call bm.DetectionContour()
            Call bm.FinMesureTemps("Detection de contour")
     
            'Pas besoin de bm.Clear car l'image est déjà entièrement blanche après la détection de contours
            Call bm.TraceContours()
            Call bm.Ecrire(My.Application.Info.DirectoryPath + "\Image2.BMP")
     
            Call bm.Clear()
            Call bm.TraceContours(True)
            Call bm.Ecrire(My.Application.Info.DirectoryPath + "\Image3.BMP")
     
            MsgBox("Terminé")
     
        End Sub
    End Class
     
    Option Explicit On
    Imports System
    Imports System.IO
     
    Public Class BMP1BIT
        Protected Largeur As UInt32
        Protected Hauteur As UInt32
        Protected nOctetsParLigne As UInt32
        Public Donnees() As Byte
        Public ListeContours As Collection
     
        Dim Debut_execution As DateTime
        Dim duree_execution As TimeSpan
     
        Public Sub New()
     
        End Sub
     
        Public Sub New(Fichier As String)
            Call Lire(Fichier)
        End Sub
     
        Public Sub New(GDI_Bitmap As Bitmap)
            Call SetFromSystemDrawingBitmap(GDI_Bitmap)
        End Sub
     
        Public Sub DemarrerMesureTemps()
            Debut_execution = DateTime.Now
        End Sub
        Public Sub FinMesureTemps(Message As String)
            duree_execution = DateTime.Now - Debut_execution
            MsgBox(Message + " terminé - durée = " + duree_execution.ToString)
        End Sub
     
        Public Sub New(LargeurX As UInt32, HauteurY As UInt32, Optional FondsBlanc As Boolean = True)
            Dim i As ULong
            Dim l As ULong
            Dim b As Byte
            Largeur = LargeurX
            Hauteur = HauteurY
            nOctetsParLigne = Fix((Largeur + 31) / 32) * 4 'nOctetsParLigne doit être multiple de 4
            l = nOctetsParLigne * Hauteur
            ReDim Donnees(l)
            If FondsBlanc Then
                b = 255
            Else
                b = 0
            End If
            For i = 0 To l - 1
                Donnees(i) = b
            Next
        End Sub
     
        Public Function Lire(Fichier As String) As Boolean
     
            Dim PixelArray_Offset As UInt32
            Dim Header_Size As UInt32
            Dim dummy() As Byte
     
            Dim tmpb As Byte
            Dim tmps As String
            Dim tmpi As UInt16
            Dim tmpl As UInt32
     
            Dim i As Integer
     
            Dim nBitsParPixel As UInt16
            Dim tailleImageOctets As UInt32
     
            Dim nOctetsParLigne2 As UInt32
            Dim x As UInt32
            Dim y As UInt32
     
            Dim R As Byte
            Dim V As Byte
            Dim B As Byte
     
            Dim DecY As UInt32
     
            'LECTURE DE L'ENTETE DU FICHIER D'ENTREE ************************************************************************
     
            Dim binReader As New BinaryReader(File.Open(Fichier, FileMode.Open))
            'Lecture de l'entête
            'Lecture des deux octets descripteur de type
            tmps = binReader.ReadChars(2)
            If tmps <> "BM" Then
                MsgBox("Le fichier " + Fichier + "n'est pas de type BMP")
                Lire = False
                Exit Function
            End If
            'Taille du fichier
            tmpl = binReader.ReadUInt32
            'Reservé
            tmpl = binReader.ReadUInt32
            'Offset de l'image
            PixelArray_Offset = binReader.ReadUInt32
            'Taille de l'entête image
            Header_Size = binReader.ReadUInt32
            'Dimenssions de l'Image
            Largeur = binReader.ReadUInt32
            Hauteur = binReader.ReadUInt32
            'Nombre de plan
            tmpi = binReader.ReadInt16
            'Nombre de bits par pixel
            nBitsParPixel = binReader.ReadInt16
            'Methode de compression
            tmpl = binReader.ReadUInt32
            If tmpl <> 0 Then
                MsgBox("Le fichier " + Fichier + "est compressé, abandon de la lecture")
                Lire = False
                Exit Function
            End If
            'Taille de l'image en octets
            tailleImageOctets = binReader.ReadUInt32
            'Résolution de l'image
            tmpl = binReader.ReadUInt32
            tmpl = binReader.ReadUInt32
            'Couleurs utilisées
            tmpl = binReader.ReadUInt32
            'Couleurs importantes :
            tmpl = binReader.ReadUInt32
     
            nOctetsParLigne = Fix((Largeur + 31) / 32) * 4 'nOctetsParLigne doit être multiple de 4
     
            Select Case nBitsParPixel
                Case 1
                    Dim CoulPalette0 As UInt16
                    Dim CoulPalette1 As UInt16
                    Dim CoulInverse As Boolean
                    Dim l As ULong
                    Dim j As ULong
     
                    'On passe les données du header que l'on utilise pas :
                    dummy = binReader.ReadBytes(Header_Size - 40)
     
                    'Lecture de la palette et conversion en noir et blanc :
                    CoulPalette0 = 0
                    CoulPalette0 = 0.3 * binReader.ReadByte                 'B
                    CoulPalette0 = CoulPalette0 + 0.59 * binReader.ReadByte 'V
                    CoulPalette0 = CoulPalette0 + 0.11 * binReader.ReadByte 'R 
                    tmpb = binReader.ReadByte
                    CoulPalette1 = 0
                    CoulPalette1 = 0.3 * binReader.ReadByte                 'B
                    CoulPalette1 = CoulPalette0 + 0.59 * binReader.ReadByte 'V
                    CoulPalette1 = CoulPalette0 + 0.11 * binReader.ReadByte 'R 
                    tmpb = binReader.ReadByte
                    CoulInverse = CoulPalette0 > CoulPalette1
                    'CoulInverse = Not CoulInverse 'Test
     
                    'On passe les données entre le header et les données images que l'on utilise pas :
                    dummy = binReader.ReadBytes(PixelArray_Offset - 62 - (Header_Size - 40))
     
                    'Lecture des données image :
                    l = nOctetsParLigne * Hauteur
                    Donnees = binReader.ReadBytes(l)
     
                    If CoulInverse Then
                        'MsgBox("Les couleurs noir et blanc sont inversées dans la palette")
                        For j = 0 To l - 1
                            Donnees(j) = Not Donnees(j)
                        Next
                    End If
     
                Case 4  'Image en 16 couleurs
     
                    Dim CoulPaletteBlanc(16) As Boolean
                    Dim CoulPalette As UInt16
                    Dim nCBlanc As Integer
                    Dim nCNoir As Integer
     
                    'On passe les données du header que l'on utilise pas :
                    dummy = binReader.ReadBytes(Header_Size - 40)
     
                    'Lecture de la palette et conversion en noir et blanc :
                    nCBlanc = 0
                    nCNoir = 0
                    For i = 0 To 15
                        CoulPalette = 0
                        CoulPalette = 0.3 * binReader.ReadByte                'B
                        CoulPalette = CoulPalette + 0.59 * binReader.ReadByte 'V
                        CoulPalette = CoulPalette + 0.11 * binReader.ReadByte 'R 
                        tmpb = binReader.ReadByte
                        'CoulPaletteBlanc(i) = CoulPalette > 127
                        If CoulPalette > 127 Then
                            CoulPaletteBlanc(i) = True
                            nCBlanc = nCBlanc + 1
                        Else
                            CoulPaletteBlanc(i) = False
                            nCNoir = nCNoir + 1
                        End If
                    Next
     
                    If nCBlanc = 0 Then
                        MsgBox("La palette du fichier " + Fichier + " ne contient que des couleurs correspondant à du noir, abandon de la lecture")
                        Lire = False
                        Exit Function
                    End If
                    If nCNoir = 0 Then
                        MsgBox("La palette du fichier " + Fichier + " ne contient que des couleurs correspondant à du blanc, abandon de la lecture")
                        Lire = False
                        Exit Function
                    End If
     
                    'On passe les données entre le header et les données images que l'on utilise pas :
                    dummy = binReader.ReadBytes(PixelArray_Offset - 118 - (Header_Size - 40))
     
                    'Lecture des données image :
     
                    nOctetsParLigne2 = Fix((Largeur * 4 + 31) / 32) * 4 'nOctetsParLigne doit être multiple de 4
                    ReDim Donnees(nOctetsParLigne * Hauteur)
                    For y = 0 To Hauteur - 1
                        i = 128
                        tmpi = 0
                        tmpb = 0
                        DecY = nOctetsParLigne * y
                        For x = 0 To Largeur - 1
                            If (x Mod 2) = 0 Then
                                'x pair
                                B = binReader.ReadByte
                                R = B >> 4
                            Else
                                'x impair
                                R = B - (R << 4)
                            End If
     
                            If CoulPaletteBlanc(R) Then
                                tmpb = tmpb + i
                            End If
                            If i = 1 Then
                                Donnees(tmpi + DecY) = tmpb
                                i = 256
                                tmpb = 0
                                tmpi = tmpi + 1
                            End If
                            i = i >> 1 'équivalent à i = i / 2
                        Next
                        'Le dernier octet :
                        Donnees(tmpi + nOctetsParLigne * y) = tmpb
                        'Les octets à 0 pour avoir une ligne multiple de 4 octets :
                        For i = tmpi + 1 To nOctetsParLigne - 1
                            Donnees(i + DecY) = 0
                        Next
                        'Lecture des octets de remplissage :
                        For i = Largeur * 3 + 1 To nOctetsParLigne2
                            tmpb = binReader.ReadByte
                        Next
                    Next
     
                Case 8 'Image en 256 couleurs (pas forcément niveaux de gris)
                    Dim CoulPaletteBlanc(256) As Boolean
                    Dim CoulPalette As UInt16
                    Dim nCBlanc As Integer
                    Dim nCNoir As Integer
     
                    'On passe les données du header que l'on utilise pas :
                    dummy = binReader.ReadBytes(Header_Size - 40)
     
                    'Lecture de la palette et conversion en noir et blanc :
                    nCBlanc = 0
                    nCNoir = 0
                    For i = 0 To 255
                        CoulPalette = 0
                        CoulPalette = 0.3 * binReader.ReadByte                'B
                        CoulPalette = CoulPalette + 0.59 * binReader.ReadByte 'V
                        CoulPalette = CoulPalette + 0.11 * binReader.ReadByte 'R 
                        tmpb = binReader.ReadByte
                        'CoulPaletteBlanc(i) = CoulPalette > 127
                        If CoulPalette > 127 Then
                            CoulPaletteBlanc(i) = True
                            nCBlanc = nCBlanc + 1
                        Else
                            CoulPaletteBlanc(i) = False
                            nCNoir = nCNoir + 1
                        End If
                    Next
     
                    If nCBlanc = 0 Then
                        MsgBox("La palette du fichier " + Fichier + " ne contient que des couleurs correspondant à du noir, abandon de la lecture")
                        Lire = False
                        Exit Function
                    End If
                    If nCNoir = 0 Then
                        MsgBox("La palette du fichier " + Fichier + " ne contient que des couleurs correspondant à du blanc, abandon de la lecture")
                        Lire = False
                        Exit Function
                    End If
     
                    'On passe les données entre le header et les données images que l'on utilise pas :
                    dummy = binReader.ReadBytes(PixelArray_Offset - 1078 - (Header_Size - 40))
     
                    'Lecture des données image :
     
                    nOctetsParLigne2 = Fix((Largeur + 1) / 4) * 4
                    ReDim Donnees(nOctetsParLigne * Hauteur)
                    For y = 0 To Hauteur - 1
                        i = 128
                        tmpi = 0
                        tmpb = 0
                        DecY = nOctetsParLigne * y
                        For x = 0 To Largeur - 1
                            If CoulPaletteBlanc(binReader.ReadByte) Then
                                tmpb = tmpb + i
                            End If
                            If i = 1 Then
                                Donnees(tmpi + DecY) = tmpb
                                i = 256
                                tmpb = 0
                                tmpi = tmpi + 1
                            End If
                            i = i >> 1 'équivalent à i = i / 2
                        Next
                        'Le dernier octet :
                        Donnees(tmpi + nOctetsParLigne * y) = tmpb
                        'Les octets à 0 pour avoir une ligne multiple de 4 octets :
                        For i = tmpi + 1 To nOctetsParLigne - 1
                            Donnees(i + DecY) = 0
                        Next
                        'Lecture des octets de remplissage :
                        For i = Largeur * 3 + 1 To nOctetsParLigne2
                            tmpb = binReader.ReadByte
                        Next
                    Next
     
                Case 24 'Image en couleurs vraies 
                    Dim tabBleu(256) As Integer
                    Dim tabVert(256) As Integer
                    Dim tabRouge(256) As Integer
     
                    'Tableaux de pré-calcul pour la conversion en niveau de gris préalable à la conversion en noir et blanc :
                    For y = 0 To 255
                        tabBleu(y) = 76 * y
                        tabVert(y) = 151 * y
                        tabRouge(y) = 28 * y
                    Next
     
                    'Lecture des données image et conversion en noir et blanc :
     
                    'On passe les données du header que l'on utilise pas :
                    dummy = binReader.ReadBytes(Header_Size - 40)
                    'On passe les données entre le header et les données images que l'on utilise pas :
                    dummy = binReader.ReadBytes(PixelArray_Offset - 54 - (Header_Size - 40))
     
                    nOctetsParLigne2 = Fix((Largeur * 3 + 3) / 4) * 4
                    ReDim Donnees(nOctetsParLigne * Hauteur)
                    For y = 0 To Hauteur - 1
                        i = 128
                        tmpi = 0
                        tmpb = 0
                        DecY = nOctetsParLigne * y
                        For x = 0 To Largeur - 1
                            B = binReader.ReadByte
                            V = binReader.ReadByte
                            R = binReader.ReadByte
                            'If CByte(0.3 * B + 0.59 * V + 0.11 * R) > 127 Then 'On allume le pixel 'On allume le pixel 
                            If (tabBleu(B) + tabVert(V) + tabRouge(R)) >> 8 > 127 Then
                                tmpb = tmpb + i
                            End If
                            If i = 1 Then
                                Donnees(tmpi + DecY) = tmpb
                                i = 256
                                tmpb = 0
                                tmpi = tmpi + 1
                            End If
                            i = i >> 1 'équivalent à i = i / 2
                        Next
                        'Le dernier octet :
                        Donnees(tmpi + nOctetsParLigne * y) = tmpb
                        'Les octets à 0 pour avoir une ligne multiple de 4 octets :
                        For i = tmpi + 1 To nOctetsParLigne - 1
                            Donnees(i + DecY) = 0
                        Next
                        'Lecture des octets de remplissage :
                        For i = Largeur * 3 + 1 To nOctetsParLigne2
                            tmpb = binReader.ReadByte
                        Next
                    Next
                Case Else
                    MsgBox("Le fichier " + Fichier + "a un codage de couleurs sur " + Format(nBitsParPixel) + " bits non pris en charge, abandon de la lecture")
                    Lire = False
                    Exit Function
     
            End Select
     
            binReader.Close()
     
            Lire = True
        End Function
     
        Public Function Ecrire(Fichier As String) As Boolean
            'ECRITURE DE L'ENTETE DU FICHIER DE SORTIE *********************************************************************
            Dim tmpb As Byte
            Dim tmpi As UInt16
            Dim tmpl As UInt32
     
            Dim binWriter As New BinaryWriter(File.Open(Fichier, FileMode.Create))
     
            'Ecriture de l'entête
            tmpi = &H4D42 : binWriter.Write(tmpi)
            'Taille du fichier
            tmpl = 54 + 1 + 8 + nOctetsParLigne * Hauteur
            binWriter.Write(tmpl)
            'Reservé
            tmpl = 0 : binWriter.Write(tmpl)
            'Offset de l'image
            tmpl = 54 + 8 : binWriter.Write(tmpl)
            'Taille de l'entête image
            tmpl = 40 : binWriter.Write(tmpl)
            'Dimenssions de l'Image
            binWriter.Write(Largeur)
            binWriter.Write(Hauteur)
            'Nombre de plan
            tmpi = 1 : binWriter.Write(tmpi)
            'Nombre de bits par pixel
            tmpi = 1 : binWriter.Write(tmpi)
            'Methode de compression
            tmpl = 0 : binWriter.Write(tmpl)
            'Taille de l'image en octets
            tmpl = nOctetsParLigne * Hauteur
            binWriter.Write(tmpl)
            'Résolution de l'image
            tmpl = 3780 : binWriter.Write(tmpl) : binWriter.Write(tmpl)
            'Couleurs utilisées
            tmpl = 2 : binWriter.Write(tmpl)
            'Couleurs importantes :
            tmpl = 0 : binWriter.Write(tmpl)
            'palette :
            'couleur 0
            tmpb = 0 : binWriter.Write(tmpb)
            tmpb = 0 : binWriter.Write(tmpb)
            tmpb = 0 : binWriter.Write(tmpb)
            tmpb = 0 : binWriter.Write(tmpb)
            'couleur 1
            tmpb = 255 : binWriter.Write(tmpb)
            tmpb = 255 : binWriter.Write(tmpb)
            tmpb = 255 : binWriter.Write(tmpb)
            tmpb = 0 : binWriter.Write(tmpb)
            'ECRITURE DES DONNEES DE L'IMAGE DU FICHIER DE SORTIE ------------------------------------------------------------
            binWriter.Write(Donnees)
            binWriter.Close()
            Ecrire = True
        End Function
     
        Public Function GetSystemDrawingBitmap1Bit(Optional AfficheInfo As Boolean = False) As Bitmap
            'Ici, on va créer un objet System.Drawing.Imaging.Bitmap à partir des données de la classe
            Dim bitmap1Bit_data As System.Drawing.Imaging.BitmapData
            Dim y As UInt32
     
            Dim Debut As DateTime
            Dim duree As TimeSpan
            If AfficheInfo Then Debut = DateTime.Now
     
            GetSystemDrawingBitmap1Bit = New Bitmap(Largeur, Hauteur, System.Drawing.Imaging.PixelFormat.Format1bppIndexed)
            bitmap1Bit_data = GetSystemDrawingBitmap1Bit.LockBits(New Rectangle(0, 0, Largeur, Hauteur), System.Drawing.Imaging.ImageLockMode.ReadWrite, System.Drawing.Imaging.PixelFormat.Format1bppIndexed)
     
            'Avec ce code, l'image est inversée comme dans un mirroir en Y :
            'System.Runtime.InteropServices.Marshal.Copy(Donnees, 0, bitmap1Bit_data.Scan0, Donnees.Length)
            'Nouveau code :
            For y = 0 To Hauteur - 1
                'System.Runtime.InteropServices.Marshal.Copy(Donnees, y * nOctetsParLigne, bitmap1Bit_data.Scan0 + y * nOctetsParLigne, nOctetsParLigne)
                System.Runtime.InteropServices.Marshal.Copy(Donnees, Donnees.Length - (y + 1) * nOctetsParLigne - 1, bitmap1Bit_data.Scan0 + y * nOctetsParLigne, nOctetsParLigne)
            Next y
     
            GetSystemDrawingBitmap1Bit.UnlockBits(bitmap1Bit_data)
     
            If AfficheInfo Then
                duree = DateTime.Now - Debut
                MsgBox("Traitement terminé - durée = " + duree.ToString)
            End If
        End Function
     
        Public Function GetSystemDrawingBitmap24Bits(Optional AfficheInfo As Boolean = False) As Bitmap
            GetSystemDrawingBitmap24Bits = GetSystemDrawingBitmap1Bit(AfficheInfo).Clone(New Rectangle(0, 0, Largeur, Hauteur), Imaging.PixelFormat.Format24bppRgb)
        End Function
     
        Public Function SetFromSystemDrawingBitmap(GDI_Bitmap As Bitmap, Optional AfficheInfo As Boolean = False) As Boolean
            Dim GDI_Bitmap1bit As Bitmap
            'Ici, on va récupérer les données d'un objet System.Drawing.Imaging.Bitmap
            Largeur = GDI_Bitmap.Width
            Hauteur = GDI_Bitmap.Height
            If GDI_Bitmap.PixelFormat = Imaging.PixelFormat.Format1bppIndexed Then
                GDI_Bitmap1bit = GDI_Bitmap
            Else
                If AfficheInfo Then MsgBox("Le bitamp a été convertit en 1 bit")
                GDI_Bitmap1bit = GDI_Bitmap.Clone(New Rectangle(0, 0, Largeur, Hauteur), Imaging.PixelFormat.Format1bppIndexed)
            End If
     
            Dim bitmap1Bit_data As System.Drawing.Imaging.BitmapData
            Dim y As UInt32
     
            Dim Debut As DateTime
            Dim duree As TimeSpan
            If AfficheInfo Then Debut = DateTime.Now
     
            nOctetsParLigne = Fix((Largeur + 31) / 32) * 4 'nOctetsParLigne doit être multiple de 4
            ReDim Donnees(nOctetsParLigne * Hauteur)
     
            bitmap1Bit_data = GDI_Bitmap1bit.LockBits(New Rectangle(0, 0, Largeur, Hauteur), System.Drawing.Imaging.ImageLockMode.ReadWrite, System.Drawing.Imaging.PixelFormat.Format1bppIndexed)
     
            For y = 0 To Hauteur - 1
                System.Runtime.InteropServices.Marshal.Copy(bitmap1Bit_data.Scan0 + y * nOctetsParLigne, Donnees, Donnees.Length - (y + 1) * nOctetsParLigne - 1, nOctetsParLigne)
            Next y
     
            GDI_Bitmap1bit.UnlockBits(bitmap1Bit_data)
     
            If AfficheInfo Then
                duree = DateTime.Now - Debut
                MsgBox("Traitement terminé - durée = " + duree.ToString)
            End If
     
            SetFromSystemDrawingBitmap = True
        End Function
     
        Public Sub DetectionContour()
            Dim sx As UInt32
            Dim sy As UInt32
            Dim decY As UInt32
            Dim trouve As Boolean
            Dim Premier As Boolean
     
            Dim fin As Boolean
     
            Dim c As Contour
     
            Dim x As UInt32
            Dim y As UInt32
     
            Dim fx As UInt32
            Dim fy As UInt32
     
            Dim direction As Integer
            '0 de gauche à droite
            '1 de bas en haut
            '2 de droite à gauche
            '3 de haut en bas
     
            Dim DebutX As UInt32
            Dim DebutY As UInt32
     
            DebutX = 0
            DebutY = 0
            ListeContours = New Collection
     
            Do
                'On cherche le premier pixel noir :
                Premier = True
                For sy = DebutY To Hauteur - 1
                    decY = sy * nOctetsParLigne
                    For sx = DebutX To Largeur - 1
                        trouve = PixelEstNoir_DecY(sx, decY)
                        If trouve Then Exit For
                    Next
                    If trouve Then Exit For
                    If Premier Then
                        Premier = False
                        DebutX = 0
                    End If
                Next
     
                If Not trouve Then Exit Do
     
                'On détecte le contour :
                c = New Contour
                'le premier point :
                x = sx
                y = sy
                Call c.AddPoint(x, y, 0)
                'le deuxième point :
                x = sx + 1
                y = sy
                Call c.AddPoint(x, y, 0)
                direction = 0
                'On évite les tests en considérant que les bords de l'image sont blancs
                Do
                    Select Case direction
                        Case 0 'de gauche à droite
                            'On teste le pixel en haut à droite :
                            fx = x
                            fy = y
                            If PixelEstNoir(fx, fy) Then
                                'le pixel en haut à droite est noir
                                'on doit tester deux autres possibilités 
                                'on teste le pixel en bas à droite :
                                fx = x
                                fy = y - 1
                                If PixelEstNoir(fx, fy) Then
                                    'le pixel en haut à droite est noir, le pixel en bas à droite est noir
                                    ' => on descend
                                    direction = 3
                                    y = y - 1
                                Else
                                    'le pixel en haut à droite est noir, le pixel en bas à droite est blanc
                                    ' => on va à droite
                                    direction = 0
                                    x = x + 1
                                End If
                            Else
                                'le pixel en haut à droite est blanc
                                ' => on monte :
                                direction = 1
                                y = y + 1
                            End If
     
                        Case 1 'de bas en haut
                            'On teste le pixel en haut à gauche :
                            fx = x - 1
                            fy = y
                            If PixelEstNoir(fx, fy) Then
                                'le pixel en haut à gauche est noir
                                'on doit tester deux autres possibilités 
                                'on teste le pixel en haut à droite :
                                fx = x
                                fy = y
                                If PixelEstNoir(fx, fy) Then
                                    'le pixel en haut à gauche est noir, le pixel en haut à droite est noir
                                    ' => on va à droite
                                    direction = 0
                                    x = x + 1
                                Else
                                    'le pixel en haut à gauche est noir, le pixel en haut à droite est blanc
                                    ' => on monte :
                                    direction = 1
                                    y = y + 1
                                End If
                            Else
                                'le pixel en haut à gauche est blanc
                                ' => on va à gauche :
                                direction = 2
                                x = x - 1
                            End If
     
                        Case 2 'de droite à gauche
                            'On teste le pixel en bas à gauche :
                            fx = x - 1
                            fy = y - 1
                            If PixelEstNoir(fx, fy) Then
                                'le pixel en bas à gauche est noir
                                'on doit tester deux autres possibilités 
                                'on teste le pixel en haut à gauche :
                                fx = x - 1
                                fy = y
                                If PixelEstNoir(fx, fy) Then
                                    'le pixel en bas à gauche est noir, le pixel en haut à gauche est noir
                                    ' => on monte :
                                    direction = 1
                                    y = y + 1
                                Else
                                    'le pixel en bas à gauche est noir, le pixel en haut à gauche est blanc
                                    ' => on va à gauche :
                                    direction = 2
                                    x = x - 1
                                End If
                            Else
                                'le pixel en bas à gauche est blanc
                                '=> on descend
                                direction = 3
                                y = y - 1
                            End If
     
                        Case 3 'de haut en bas
                            'On teste le pixel en bas à droite :
                            fx = x
                            fy = y - 1
                            If PixelEstNoir(fx, fy) Then
                                'le pixel en bas à droite est noir
                                'on doit tester deux autres possibilités 
                                'on teste le pixel en bas à gauche :
                                fx = x - 1
                                fy = y - 1
                                If PixelEstNoir(fx, fy) Then
                                    'le pixel en bas à droite est noir, le pixel en bas à gauche est noir
                                    ' => on va à gauche :
                                    direction = 2
                                    x = x - 1
                                Else
                                    'le pixel en bas à droite est noir, le pixel en bas à gauche est blanc
                                    '=> on descend
                                    direction = 3
                                    y = y - 1
                                End If
                            Else
                                'le pixel en bas à droite est blanc
                                ' => on va à droite
                                direction = 0
                                x = x + 1
                            End If
                    End Select
                    fin = c.AddPoint(x, y, direction)
     
                Loop Until fin
     
                Call ListeContours.Add(c)
     
                'On inverse tous les pixels contenus dans le contour :
                'VOIR ALGORITHME POT DE PEINTURE
                Call CalculerCouplesContour(c)
                Call InverserContour(c)
     
                DebutX = sx
                DebutY = sy
     
     
            Loop
     
            If ListeContours.Count = 0 Then MsgBox("Aucun contour trouvé")
     
        End Sub
     
        Public Function PixelEstNoir(x As UInt32, y As UInt32) As Boolean
            PixelEstNoir = ((Donnees(y * nOctetsParLigne + (x >> 3)) And (1 << (7 - (x And 7)))) = 0)
        End Function
        Public Sub MettrePixelNoir(x As UInt32, y As UInt32)
            Dim i As UInt32
            i = (x >> 3) + y * nOctetsParLigne
            Donnees(i) = Donnees(i) And Not (1 << (7 - (x And 7)))
        End Sub
        Public Sub InverserPixel(x As UInt32, y As UInt32)
            Dim i As UInt32
            i = (x >> 3) + y * nOctetsParLigne
            Donnees(i) = Donnees(i) Xor (1 << (7 - (x And 7)))
        End Sub
     
        Public Function PixelEstNoir_DecY(x As UInt32, DecY As UInt32) As Boolean
            PixelEstNoir_DecY = ((Donnees(DecY + (x >> 3)) And (1 << (7 - (x And 7)))) = 0)
        End Function
        Public Sub MettrePixelNoir_DecY(x As UInt32, DecY As UInt32)
            Dim i As UInt32
            i = (x >> 3) + DecY
            Donnees(i) = Donnees(i) And Not (1 << (7 - (x And 7)))
        End Sub
        Public Sub InverserPixel_DecY(x As UInt32, DecY As UInt32)
            Dim i As UInt32
            i = (x >> 3) + DecY
            Donnees(i) = Donnees(i) Xor (1 << (7 - (x And 7)))
        End Sub
     
        Public Function Test() As BMP1BIT
            Dim bm = New BMP1BIT(Largeur, Hauteur)
            Dim x As UInt32
            Dim y As UInt32
            For y = 0 To Hauteur - 1
                For x = 0 To Largeur - 1
                    If PixelEstNoir(x, y) Then
                        bm.MettrePixelNoir(x, y)
                    End If
                Next
            Next
            Test = bm
        End Function
     
        Public Sub TraceContours(Optional Peindre As Boolean = False)
            Dim c As Contour
            Dim p As Point
            Dim x As UInt32
            Dim y As UInt32
            If Peindre Then
                For Each c In ListeContours
                    InverserContour(c)
                Next
            Else
                For Each c In ListeContours
                    For Each p In c.ListePoints
                        Select Case p.Direction
                            'La direction du point p(i) indique le sens du vecteur p(i-1)p(i)
                            'Le pixel à peindre en noir est à gauche du vecteur
                            'p.X et p.Y correspondent aux coordonnées des coins entre les pixels, et non pas aux centres des pixels
                            'le pixel de centre (0,0) a aux quatre coins des points de coordonnées (0,0) (0,1) (1,1) (1,0)
                            Case 0 'vers la droite
                                x = p.X - 1
                                y = p.Y
                            Case 1 'vers le haut
                                x = p.X - 1
                                y = p.Y - 1
                            Case 2 'vers la gauche
                                x = p.X
                                y = p.Y - 1
                            Case 3 'vers le bas
                                x = p.X
                                y = p.Y
                        End Select
                        MettrePixelNoir(x, y)
                    Next
                Next
            End If
        End Sub
     
        Public Sub CalculerCouplesContour(c As Contour)
            'Il faut peindre l'intérieur du contour, c'est à dire inverser la valeur de tous les pixels contenus dans le contour
            'On procéde pour chaque seguement de droite contenu dans le contour
            'Il faut d'abord faire la liste des vecteurs vers le haut (B,D,F,H) et des vecteurs vers le bas (A,C,E,G)
            'Ensuite on forme des couples de vecteurs (A,B) (C,D) (E,F) (G,H)
            'Puis on inverse les seguements de droite entre chaque couple de vecteur
            '------------------------------------------------------------------------
            '-----------A***************************B------------C*****D-------------
            '-------E******************************************************F---------
            '---------------G***********************H--------------------------------
            '------------------------------------------------------------------------
     
            Dim ListeH As Collection
            Dim ListeB As Collection
            Dim p As Point
            Dim p2 As Point
            Dim p3 As Point
            Dim cp As CouplePoint
            'La direction du point p(i) indique le sens du vecteur p(i-1)p(i)
            'le point p(i) désigne aussi le vecteur p(i-1)p(i)
     
            'Liste des vecteurs :
            ListeH = New Collection
            ListeB = New Collection
            For Each p In c.ListePoints
                Select Case p.Direction
                    Case 1 'vers le haut
                        ListeH.Add(p)
                    Case 3 'vers le bas
                        ListeB.Add(p)
                End Select
            Next
     
            If ListeB.Count = ListeH.Count Then
                'Formation des couples :
                c.ListeCouple = New Collection
                For Each p In ListeH
                    'Il faut chercher le point p3 correspondant au couple p,p3
                    p3 = Nothing
                    For Each p2 In ListeB
                        'On teste si p et p2 sont sur la même ligne
                        If p.Y = p2.Y + 1 Then
                            'On teste si p et p2 sont dans le bon sens
                            If p2.X < p.X Then
                                If p3 Is Nothing Then
                                    p3 = p2
                                Else
                                    'If p.X - p2.X < p.X - p3.X Then
                                    If p2.X > p3.X Then
                                        p3 = p2
                                    End If
                                End If
                            End If
                        End If
                    Next
                    If p3 Is Nothing Then
                        MsgBox("Erreur - impossible de former un couple")
                    Else
                        cp = New CouplePoint(p, p3)
                        c.ListeCouple.Add(cp)
                    End If
                Next
            Else
                MsgBox("Erreur - le nombre de vecteurs vers le haut est différent du nombre de vecteurs vers le bas")
            End If
     
        End Sub
     
        Public Sub InverserContour(c As Contour)
            Dim x As UInt32
            Dim decY As UInt32
            Dim cp As CouplePoint
            For Each cp In c.ListeCouple
                decY = cp.PB.Y * nOctetsParLigne
                For x = cp.PB.X To cp.PH.X - 1
                    Call InverserPixel_DecY(x, decY)
                Next
            Next
        End Sub
     
        Public Sub InverserContour2(c As Contour)
            'Aucune diminution de la durée d'execution avec ce code pourtant optimisé :
            Dim x As UInt32
            Dim x1 As UInt32
            Dim x2 As UInt32
            Dim decY As UInt32
            Dim cp As CouplePoint
            For Each cp In c.ListeCouple
                decY = cp.PB.Y * nOctetsParLigne
                x1 = cp.PB.X
                x2 = cp.PH.X - 1
                If x2 - x1 < 17 Then
                    For x = x1 To x2
                        Call InverserPixel_DecY(x, decY)
                    Next
                Else
                    Dim i1 As UInt32
                    Dim i2 As UInt32
                    Dim i As UInt32
                    Dim x3 As UInt32
                    Dim x4 As UInt32
                    i1 = (x1 >> 3) + 1
                    i2 = (x2 >> 3) - 1
                    x3 = (i1 << 3) - 1
                    x4 = (i2 << 3) + 8
                    i1 = i1 + decY
                    i2 = i2 + decY
                    For x = x1 To x3
                        Call InverserPixel_DecY(x, decY)
                    Next
                    For i = i1 To i2
                        Donnees(i) = Donnees(i) Xor 255
                    Next
                    For x = x2 To x4
                        Call InverserPixel_DecY(x, decY)
                    Next
                    'For x = x1 To x2
                    'Call InverserPixel_DecY(x, decY)
                    'Next
     
                End If
            Next
        End Sub
     
        Public Sub Clear()
            Dim i As ULong
            Dim l As ULong
            l = nOctetsParLigne * Hauteur - 1
            For i = 0 To l
                Donnees(i) = 255
            Next
        End Sub
     
        Public Function TraceContours2() As BMP1BIT
            Dim bm = New BMP1BIT(Largeur, Hauteur)
            Dim c As Contour
            Dim p1 As Point
            Dim p2 As Point
            Dim x As UInt32
            Dim y As UInt32
            Dim i As Integer
            For Each c In ListeContours
                For i = 1 To c.ListePoints.Count
                    'ici on va mettre au noir les pixels juste à l'intérieur du contour
                    If i = 1 Then
                        p1 = c.ListePoints.Item(c.ListePoints.Count)
                    Else
                        p1 = c.ListePoints.Item(i - 1)
                    End If
                    p2 = c.ListePoints.Item(i)
                    If p1.X = p2.X Then
                        If p1.Y < p2.Y Then
                            'Vers le haut
                            x = p1.X - 1
                            y = p1.Y
                        Else
                            'Vers le bas
                            x = p1.X
                            y = p1.Y - 1
                        End If
                    Else
                        If p1.X < p2.X Then
                            'Vers la droite
                            x = p1.X
                            y = p1.Y
                        Else
                            'Vers la gauche
                            x = p1.X - 1
                            y = p1.Y - 1
                        End If
                    End If
                    bm.MettrePixelNoir(x, y)
                Next
            Next
            TraceContours2 = bm
        End Function
    End Class
     
    Public Class Contour
        Public ListePoints As Collection
        Protected X1 As UInt32
        Protected Y1 As UInt32
     
        Public ListeCouple As Collection
     
        Public Sub New()
            ListePoints = New Collection
        End Sub
     
        Public Function AddPoint(X As UInt32, Y As UInt32, D As Integer) As Boolean
            Dim P As Point
            AddPoint = False
            If ListePoints.Count = 0 Then
                P = New Point(X, Y, D)
                ListePoints.Add(P)
                X1 = X
                Y1 = Y
                'La direction associée à ce point sera connue plus tard
            Else
                If X = X1 And Y = Y1 Then
                    'Le contour est fermé :
                    P = ListePoints.Item(1)
                    P.Direction = D
                    AddPoint = True
                Else
                    P = New Point(X, Y, D)
                    ListePoints.Add(P)
                End If
            End If
        End Function
    End Class
     
    Public Class Point
        Public X As UInt32
        Public Y As UInt32
        Public Direction As Integer
     
        Public Sub New()
     
        End Sub
        Public Sub New(PX As UInt32, PY As UInt32, Pdir As Integer)
            X = PX
            Y = PY
            Direction = Pdir
        End Sub
    End Class
     
    Public Class CouplePoint
        Public PH As Point
        Public PB As Point
     
        Public Sub New()
     
        End Sub
        Public Sub New(PointHaut As Point, PointBas As Point)
            PH = PointHaut
            PB = PointBas
        End Sub
    End Class

    Voici un test - l'image de départ en 256 niveaux de gris

    Nom : ImageDeDepart.gif
Affichages : 3349
Taille : 5,3 Ko

    L'image convertie en noir et blanc :

    Nom : Image1_Convertion1bit.gif
Affichages : 3886
Taille : 1,9 Ko

    Les contours détectés :

    Nom : Image2_Contours.gif
Affichages : 3386
Taille : 2,1 Ko

    Les contours peints :

    Nom : Image1_Convertion1bit.gif
Affichages : 3886
Taille : 1,9 Ko

    J'ai réussit ici à obtenir des contours, sous forme de polygones avec des côtés de 1 pixel de longueur. Il me reste à optimiser ces polygônes, c'est à dire réduire le nombre de côté tout en ayant un résultat correct et sans marches d'escaliers.

    Edition jeudi 1er mai à 17h45 : quelques améliorations (effacement de l'image avant traçage des contours remplis, suppression de la récursivité de la détection de contour inutile et remplacement par une boucle, ...)
    A+
    Quand deux personnes échangent un euro, chacun repart avec un euro.
    Quand deux personnes échangent une idée, chacun repart avec deux idées.

  12. #12
    Membre éprouvé Avatar de electroremy
    Homme Profil pro
    Ingénieur sécurité
    Inscrit en
    Juin 2007
    Messages
    934
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Doubs (Franche Comté)

    Informations professionnelles :
    Activité : Ingénieur sécurité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2007
    Messages : 934
    Points : 1 274
    Points
    1 274
    Par défaut
    Bonjour, la première version de mon programme est terminée

    Voici :
    - la documentation complète (mode d'emploi, formats de fichiers, algorithmes) : http://www.remylucas.fr/BTP4M_Manuel.pdf
    - l’exécutable win 32 : http://www.remylucas.fr/BTP4M_Release.zip (la mise à jour du framework .net sera peut être nécessaire sur votre PC)
    - le code source : http://www.remylucas.fr/BTP4M_CodeSource.zip

    Fonctionnalités :
    - lecture et écriture d'image bitmap 1bit, 8 bits et 24 bits
    - conversion en noir et blanc
    - détection de contours
    - algorithme de flood fill efficace
    - lissage et optimisation de contours
    - sauvegarde au format SVG
    - aucune utilisation des fonctions graphiques de VB et de Windows
    - aucune utilisation de DLL

    A noter que le programme n’est pas encore dans sa version finale. J’ai des améliorations en vue, et une version en C++ sera faite ce qui permettra de l’exécuter sur des machines n’utilisant pas Windows.

    PS : merci aux pros de ce forum de m'indiquer si une section du forum ou du site serait plus appropriée pour mettre en ligne ce programme

    A+
    Quand deux personnes échangent un euro, chacun repart avec un euro.
    Quand deux personnes échangent une idée, chacun repart avec deux idées.

  13. #13
    Modérateur
    Avatar de ToTo13
    Homme Profil pro
    Chercheur en informatique
    Inscrit en
    Janvier 2006
    Messages
    5 793
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : Etats-Unis

    Informations professionnelles :
    Activité : Chercheur en informatique
    Secteur : Santé

    Informations forums :
    Inscription : Janvier 2006
    Messages : 5 793
    Points : 9 860
    Points
    9 860
    Par défaut
    Merci de partager ton programme.
    Tu peux mettre le code source dans la rubrique Contribuez, il faudra juste expliquer le but et la manière dont tu t'y prends afin que ce soit compréhensible. Pour cela tu pourrais mettre un lien vers cette discussion.
    Consignes aux jeunes padawans : une image vaut 1000 mots !
    - Dans ton message respecter tu dois : les règles de rédaction et du forum, prévisualiser, relire et corriger TOUTES les FAUTES (frappes, sms, d'aurteaugrafe, mettre les ACCENTS et les BALISES) => ECRIRE clairement et en Français tu DOIS.
    - Le côté obscur je sens dans le MP => Tous tes MPs je détruirai et la réponse tu n'auras si en privé tu veux que je t'enseigne.(Lis donc ceci)
    - ton poste tu dois marquer quand la bonne réponse tu as obtenu.

  14. #14
    Membre à l'essai
    Inscrit en
    Septembre 2009
    Messages
    2
    Détails du profil
    Informations forums :
    Inscription : Septembre 2009
    Messages : 2
    Points : 11
    Points
    11
    Par défaut
    Citation Envoyé par electroremy Voir le message
    Bonjour, la première version de mon programme est terminée

    Voici :
    - la documentation complète (mode d'emploi, formats de fichiers, algorithmes) : http://www.remylucas.fr/BTP4M_Manuel.pdf
    - l’exécutable win 32 : http://www.remylucas.fr/BTP4M_Release.zip (la mise à jour du framework .net sera peut être nécessaire sur votre PC)
    - le code source : http://www.remylucas.fr/BTP4M_CodeSource.zip

    Fonctionnalités :
    - lecture et écriture d'image bitmap 1bit, 8 bits et 24 bits
    - conversion en noir et blanc
    - détection de contours
    - algorithme de flood fill efficace
    - lissage et optimisation de contours
    - sauvegarde au format SVG
    - aucune utilisation des fonctions graphiques de VB et de Windows
    - aucune utilisation de DLL

    A noter que le programme n’est pas encore dans sa version finale. J’ai des améliorations en vue, et une version en C++ sera faite ce qui permettra de l’exécuter sur des machines n’utilisant pas Windows.

    PS : merci aux pros de ce forum de m'indiquer si une section du forum ou du site serait plus appropriée pour mettre en ligne ce programme

    A+

    S'il vous plaît partager un nouveau lien pour télécharger ce logiciel, lien ne fonctionne pas, Merci!!!
    Ma copie de fichier est perdue sur le disque, Mercy

  15. #15
    Modérateur
    Avatar de ToTo13
    Homme Profil pro
    Chercheur en informatique
    Inscrit en
    Janvier 2006
    Messages
    5 793
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : Etats-Unis

    Informations professionnelles :
    Activité : Chercheur en informatique
    Secteur : Santé

    Informations forums :
    Inscription : Janvier 2006
    Messages : 5 793
    Points : 9 860
    Points
    9 860
    Par défaut
    Et si tu regardais directement sur la page de Rémy Lucas vu que c'est son site ?
    Consignes aux jeunes padawans : une image vaut 1000 mots !
    - Dans ton message respecter tu dois : les règles de rédaction et du forum, prévisualiser, relire et corriger TOUTES les FAUTES (frappes, sms, d'aurteaugrafe, mettre les ACCENTS et les BALISES) => ECRIRE clairement et en Français tu DOIS.
    - Le côté obscur je sens dans le MP => Tous tes MPs je détruirai et la réponse tu n'auras si en privé tu veux que je t'enseigne.(Lis donc ceci)
    - ton poste tu dois marquer quand la bonne réponse tu as obtenu.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Détection de nouveaux contours entrés dans une image
    Par dindoopenCV dans le forum OpenCV
    Réponses: 6
    Dernier message: 03/07/2013, 10h49
  2. Détection de forme géométriques dans une image
    Par imeneeeee dans le forum Images
    Réponses: 9
    Dernier message: 19/01/2010, 09h39
  3. détection d'un visage dans une image
    Par salmatr dans le forum Images
    Réponses: 2
    Dernier message: 04/08/2009, 00h05
  4. [Débutant] Détection de panneaux routiers dans une image
    Par syl55 dans le forum Images
    Réponses: 1
    Dernier message: 05/05/2009, 00h17
  5. Détection position des yeux dans une image
    Par Morvan Mikael dans le forum Traitement d'images
    Réponses: 16
    Dernier message: 24/12/2008, 23h09

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo