Convertir une image en niveau de gris

Soyez le premier à donner votre avis sur cette source.

Snippet vu 21 530 fois - Téléchargée 25 fois


Contenu du snippet

On peut convertir une image couleur en niveau de gris via une formule empirique liée aux composantes Bleu, vert, Rouge de l'image :

0.3 * bleu + 0.59 * vert + 0.11 rouge = niveau de gris

Cette formule peut être très largement améliorée, pour ne pas multiplier des nombres à virgules ( ce qui est coûteux en performance), en multipliant les coefficients par 256. On redivise le tout par 256 par la suite.

Source / Exemple :


Dim bitmaptest As Bitmap = New Bitmap("d:\image.jpg")
        Dim bitmap As Bitmap = New Bitmap(bitmaptest) 'transforme en 32 bits :)

        Dim width As Integer = bitmap.Width
        Dim height As Integer = bitmap.Height

        'création de l'image 8 bits contenant le résultat
        Dim bitmapNivGris As Bitmap = New Bitmap(width, height, PixelFormat.Format8bppIndexed)

        'Récupération de la palette 256 couleurs
        Dim pal As ColorPalette = bitmapNivGris.Palette

        Dim i As Integer
        'Redéfinition de la palette
        For i = 0 To 255
            pal.Entries(i) = Color.FromArgb((255 << 24) Or (i << 16) Or (i << 8) Or i)
        Next
        'Réaffectation de la palette à l'image 
        'car on ne possédait pas une référence (utilisez Reflector sur la Palette pour comprendre)
        bitmapNivGris.Palette = pal

        'Lockbits des images initial et résultat
        Dim bmpDataOld As BitmapData = bitmap.LockBits(New Rectangle(0, 0, width, height) _
        , System.Drawing.Imaging.ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb)
        Dim bmpDataNew As BitmapData = bitmapNivGris.LockBits(New Rectangle(0, 0, width, height) _
        , ImageLockMode.ReadWrite, PixelFormat.Format8bppIndexed)

        'Copie des pixels dans un tableau contenant tous les composantes Bleu, vert, rouge, alpha
        Dim oldPixel(width * height - 1) As Integer '4 octets = 4 composantes = 1 pixel
        Marshal.Copy(bmpDataOld.Scan0, oldPixel, 0, oldPixel.Length)

        Dim newPixel(bmpDataNew.Stride * height - 1) As Byte '1 octet = 1 pixel
        'Pas necessaire de recuperer les donnees de l'image vierge par un Marshal.Copy :-)

        Dim locOld, x, y As Integer

        'tables de precalcul des multiplications pour le calcul de localisation des pixels
        'de l'ancienne image et de la nouvelle.
        Dim multiOld(height - 1) As Integer
        Dim multiNew(height - 1) As Integer

        For y = 0 To height - 1
            multiOld(y) = width * y
            multiNew(y) = bmpDataNew.Stride * y
        Next

        'tables de precalcul des multiplications pour le calcul du niveau de gris
        Dim tabBleu(255) As Integer
        Dim tabVert(255) As Integer
        Dim tabRouge(255) As Integer

        'Initialisation
        For y = 0 To 255
            tabBleu(y) = 76 * y
            tabVert(y) = 151 * y
            tabRouge(y) = 28 * y
        Next

        For y = 0 To height - 1

            For x = 0 To width - 1
                'calcul de la localisation du pixel
                locOld = multiOld(y) + x
                'on calcule le niveau de gris sur 255 
                'Formule ci-dessous en commentaires, à éviter car coûteuse
                'CByte(0.3 * oldPixel(loc) + 0.59 * oldPixel(loc + 1) + 0.11 * oldPixel(loc + 2))

                'on affecte le niveau de gris au pixel dans la nouvelle image
                newPixel(multiNew(y) + x) = (tabBleu(oldPixel(locOld) And &HFF) + tabVert((oldPixel(locOld) And &HFF00) >> 8) + tabRouge((oldPixel(locOld) And &HFF0000) >> 16)) >> 8

            Next

        Next

        'on recopie notre nouveau tableau dans la nouvelle image
        Marshal.Copy(newPixel, 0, bmpDataNew.Scan0, newPixel.Length)

        bitmapNivGris.UnlockBits(bmpDataNew)
        bitmap.UnlockBits(bmpDataOld)

Conclusion :


L'image résultat est bitmapNivGris.

A voir également

Ajouter un commentaire Commentaires
Messages postés
13280
Date d'inscription
lundi 13 décembre 2004
Statut
Modérateur
Dernière intervention
3 février 2018
36
salut,

pas de zip, il te faut juste copier le code dans l'IDE VB.NET puis compiler toi-même le projet

PAS d'EXE : http://www.vbfrance.com/doc/faq.aspx#cs_noexe
Où TROUVER VS/VB : http://www.vbfrance.com/doc/faq.aspx#vb_lastide
QUE CONTIENT UN ZIP : http://www.vbfrance.com/doc/faq.aspx#vb_src
Messages postés
29
Date d'inscription
lundi 30 juin 2003
Statut
Membre
Dernière intervention
25 juillet 2014
2
super mais ou est l'exécutable ?
Messages postés
9
Date d'inscription
mercredi 5 janvier 2005
Statut
Modérateur
Dernière intervention
19 décembre 2007

Rapide et simple, oui, si on reste au format 32 bits. Par contre, si on veut sauvegarder l'image avec la taille la plus réduite possible, le format 8 bits indexé est sans aucun doute plus approprié...
Brunews apporte sans contestation une augmentation de la performance. Même si ce ne sont que quelques millisecondes sur une image de faible taille, cela pourait représenter quelques dixièmes de secondes sur une image plus importante.
Messages postés
167
Date d'inscription
jeudi 9 décembre 2004
Statut
Membre
Dernière intervention
18 novembre 2007
1
Passer par les colormatrix serait beaucoup plus rapide (et simple) non ?
Messages postés
21042
Date d'inscription
jeudi 23 janvier 2003
Statut
Modérateur
Dernière intervention
21 août 2019
24
On pourrait encore gagner 256 comparaisons 'y <= 255 ?' en bas de boucle.
Il faut pour cela changer FOR par un DO LOOP afin de tendre vers 0, le compilo devrait donner un code nettement plus valable.
Pourquoi (le NEXT vb):
For y = 0 To 255
'bla bla bla
Next
vaut compilé:
xor ebx, ebx
FORy:
; bla bla bla
inc ebx
cmp ebx, 255
jbe FORy ; LE BOUCLAGE NEXT VB

Si on tendait vers 0:
yZERO:
; bla bla bla
dec ebx
jns yZERO

Le benef est tout net d'une comparaison par tour.
Pour cela placer au début B, V et R aux valeurs maxi, les décrémenter à chaque tour (76, 151 et 28).
Now je passe en syntaxe C, souvenirs VB trop lointains, tu traduiras:
y = 255;
do {
tabBleu[y] = B;
tabVert[y] = V;
tabRouge[y] = R;
B -= 76;
V -= 151;
R -= 28;
} while(--y >= 0);
Afficher les 8 commentaires

Vous n'êtes pas encore membre ?

inscrivez-vous, c'est gratuit et ça prend moins d'une minute !

Les membres obtiennent plus de réponses que les utilisateurs anonymes.

Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.

Le fait d'être membre vous permet d'avoir des options supplémentaires.