Recherche…


Introduction

Le package d' image fournit des fonctionnalités de base pour travailler avec une image 2D. Cette rubrique décrit plusieurs opérations de base lors de l'utilisation d'images telles que la lecture et l'écriture d'un format d'image particulier, le recadrage, l'accès et la modification de pixels , la conversion de couleurs, le redimensionnement et le filtrage d'image de base.

Concepts de base

Une image représente une grille rectangulaire d'éléments d'image ( pixel ). Dans le package d' image , le pixel est représenté comme l'une des couleurs définies dans le package image / couleur . La géométrie 2D de l'image est représentée sous la forme image.Rectangle , tandis que image.Point indique une position sur la grille.

Image et géométrie 2D

La figure ci-dessus illustre les concepts de base d'une image dans le package. Une image de taille 15x14 pixels a des limites rectangulaires au coin supérieur gauche (par exemple, coordonnée (-3, -4) dans la figure ci-dessus), et ses axes augmentent vers le bas et le coin droit (par exemple, coordonnée ( 12, 10) sur la figure). Notez que les limites ne partent pas nécessairement du point (0,0) .

Type lié à l'image

Dans Go , une image implémente toujours l'interface suivante image.Image

type Image interface {
    // ColorModel returns the Image's color model.
    ColorModel() color.Model
    // Bounds returns the domain for which At can return non-zero color.
    // The bounds do not necessarily contain the point (0, 0).
    Bounds() Rectangle
    // At returns the color of the pixel at (x, y).
    // At(Bounds().Min.X, Bounds().Min.Y) returns the upper-left pixel of the grid.
    // At(Bounds().Max.X-1, Bounds().Max.Y-1) returns the lower-right one.
    At(x, y int) color.Color
}

dans lequel l'interface color.Color est définie comme

type Color interface {
    // RGBA returns the alpha-premultiplied red, green, blue and alpha values
    // for the color. Each value ranges within [0, 0xffff], but is represented
    // by a uint32 so that multiplying by a blend factor up to 0xffff will not
    // overflow.
    //
    // An alpha-premultiplied color component c has been scaled by alpha (a),
    // so has valid values 0 <= c <= a.
    RGBA() (r, g, b, a uint32)
}

et color.Model est une interface déclarée comme

type Model interface {
    Convert(c Color) Color
}

Accéder à la dimension de l'image et au pixel

Supposons que nous ayons une image stockée en tant que variable img , alors nous pouvons obtenir la dimension et l'image en pixel par:

// Image bounds and dimension
b := img.Bounds()
width, height := b.Dx(), b.Dy()
// do something with dimension ...

// Corner co-ordinates
top := b.Min.Y
left := b.Min.X
bottom := b.Max.Y
right := b.Max.X
    
// Accessing pixel. The (x,y) position must be
// started from (left, top) position not (0,0)
for y := top; y < bottom; y++ {
    for x := left; x < right; x++ {
        cl := img.At(x, y)
        r, g, b, a := cl.RGBA()
        // do something with r,g,b,a color component
    }
}

Notez que dans le package, la valeur de chaque composant R,G,B,A est comprise entre 0-65535 ( 0x0000 - 0xffff ) et non 0-255 .

Chargement et sauvegarde de l'image

En mémoire, une image peut être vue comme une matrice de pixel (couleur). Cependant, lorsqu'une image est stockée dans un stockage permanent, elle peut être stockée telle quelle (format RAW), Bitmap ou d'autres formats d'image avec un algorithme de compression particulier pour économiser de l'espace de stockage, par exemple PNG, JPEG, GIF, etc. avec un format particulier, l'image doit être décodée en image.Image avec l'algorithme correspondant. Une fonction image.Decode déclarée comme

func Decode(r io.Reader) (Image, string, error)

est fourni pour cet usage particulier. Pour pouvoir traiter divers formats d'image, avant d'appeler la fonction image.Decode , le décodeur doit être enregistré via la fonction image.RegisterFormat définie comme suit:

func RegisterFormat(name, magic string, 
    decode func(io.Reader) (Image, error), decodeConfig func(io.Reader) (Config, error))

Actuellement, le package d'image prend en charge trois formats de fichier: JPEG , GIF et PNG . Pour enregistrer un décodeur, ajoutez ce qui suit

import _ "image/jpeg"    //register JPEG decoder

au package main l'application. Quelque part dans votre code (pas nécessaire dans main package main ), pour charger une image JPEG, utilisez les extraits suivants:

f, err := os.Open("inputimage.jpg")
if err != nil {
    // Handle error
}
defer f.Close()

img, fmtName, err := image.Decode(f)
if err != nil {
    // Handle error
}

// `fmtName` contains the name used during format registration
// Work with `img` ...

Enregistrer dans PNG

Pour enregistrer une image dans un format particulier, l' encodeur correspondant doit être importé explicitement, c.-à-d.

import "image/png"    //needed to use `png` encoder

Une image peut alors être enregistrée avec les extraits suivants:

f, err := os.Create("outimage.png")
if err != nil {
    // Handle error
}
defer f.Close()

// Encode to `PNG` with `DefaultCompression` level
// then save to file
err = png.Encode(f, img)
if err != nil {
    // Handle error
}

Si vous souhaitez spécifier un niveau de compression autre que le niveau DefaultCompression , créez un encodeur , par exemple

enc := png.Encoder{
    CompressionLevel: png.BestSpeed,
}
err := enc.Encode(f, img)

Enregistrer au format JPEG

Pour enregistrer au format jpeg , utilisez ce qui suit:

import "image/jpeg"

// Somewhere in the same package
f, err := os.Create("outimage.jpg")
if err != nil {
    // Handle error
}
defer f.Close()

// Specify the quality, between 0-100
// Higher is better
opt := jpeg.Options{
    Quality: 90,
}
err = jpeg.Encode(f, img, &opt)
if err != nil {
    // Handle error
}

Enregistrer dans GIF

Pour enregistrer l'image dans un fichier GIF, utilisez les extraits suivants.

import "image/gif"

// Samewhere in the same package
f, err := os.Create("outimage.gif")
if err != nil {
    // Handle error
}
defer f.Close()

opt := gif.Options {
    NumColors: 256, 
    // Add more parameters as needed
}

err = gif.Encode(f, img, &opt)
if err != nil {
    // Handle error
}

Image recadrée

La plupart des types d' image dans le package d' image ayant la SubImage(r Rectangle) Image image SubImage(r Rectangle) Image , sauf image.Uniform . Sur cette base, nous pouvons implémenter une fonction pour recadrer une image arbitraire comme suit

func CropImage(img image.Image, cropRect image.Rectangle) (cropImg image.Image, newImg bool) {
    //Interface for asserting whether `img`
    //implements SubImage or not.
    //This can be defined globally.
    type CropableImage interface {
        image.Image
        SubImage(r image.Rectangle) image.Image
    }

    if p, ok := img.(CropableImage); ok {
        // Call SubImage. This should be fast,
        // since SubImage (usually) shares underlying pixel.
        cropImg = p.SubImage(cropRect)
    } else if cropRect = cropRect.Intersect(img.Bounds()); !cropRect.Empty() {
        // If `img` does not implement `SubImage`,
        // copy (and silently convert) the image portion to RGBA image.
        rgbaImg := image.NewRGBA(cropRect)
        for y := cropRect.Min.Y; y < cropRect.Max.Y; y++ {
            for x := cropRect.Min.X; x < cropRect.Max.X; x++ {
                rgbaImg.Set(x, y, img.At(x, y))
            }
        }
        cropImg = rgbaImg
        newImg = true
    } else {
        // Return an empty RGBA image
        cropImg = &image.RGBA{}
        newImg = true
    }

    return cropImg, newImg
}

Notez que l'image recadrée peut partager ses pixels sous-jacents avec l'image d'origine. Si tel est le cas, toute modification de l'image recadrée affectera l'image d'origine.

Convertir une image couleur en niveaux de gris

Certains algorithmes de traitement d'images numériques, tels que la détection des contours, les informations portées par l'intensité de l'image (valeur d'échelle de gris) sont suffisants. L'utilisation des informations de couleur (canal R, G, B ) peut fournir un résultat légèrement meilleur, mais la complexité de l'algorithme sera accrue. Ainsi, dans ce cas, nous devons convertir l'image couleur en image en niveaux de gris avant d'appliquer un tel algorithme.

Le code suivant est un exemple de conversion d'image arbitraire en image en niveaux de gris de 8 bits. L'image est extraite de l'emplacement distant en utilisant net/http package net/http , convertie en niveaux de gris et finalement enregistrée en tant qu'image PNG.

package main

import (
    "image"
    "log"
    "net/http"
    "os"

    _ "image/jpeg"
    "image/png"
)

func main() {
    // Load image from remote through http
    // The Go gopher was designed by Renee French. (http://reneefrench.blogspot.com/)
    // Images are available under the Creative Commons 3.0 Attributions license.
    resp, err := http.Get("http://golang.org/doc/gopher/fiveyears.jpg")
    if err != nil {
        // handle error
        log.Fatal(err)
    }
    defer resp.Body.Close()

    // Decode image to JPEG
    img, _, err := image.Decode(resp.Body)
    if err != nil {
        // handle error
        log.Fatal(err)
    }
    log.Printf("Image type: %T", img)

    // Converting image to grayscale
    grayImg := image.NewGray(img.Bounds())
    for y := img.Bounds().Min.Y; y < img.Bounds().Max.Y; y++ {
        for x := img.Bounds().Min.X; x < img.Bounds().Max.X; x++ {
            grayImg.Set(x, y, img.At(x, y))
        }
    }

    // Working with grayscale image, e.g. convert to png
    f, err := os.Create("fiveyears_gray.png")
    if err != nil {
        // handle error
        log.Fatal(err)
    }
    defer f.Close()

    if err := png.Encode(f, grayImg); err != nil {
        log.Fatal(err)
    }
}

La conversion de couleur se produit lors de l’attribution de pixels via Set(x, y int, c color.Color) implémentée dans image.go as

func (p *Gray) Set(x, y int, c color.Color) {
    if !(Point{x, y}.In(p.Rect)) {
        return
    }

    i := p.PixOffset(x, y)
    p.Pix[i] = color.GrayModel.Convert(c).(color.Gray).Y
}

dans lequel color.GrayModel est défini dans color.go comme

func grayModel(c Color) Color {
    if _, ok := c.(Gray); ok {
        return c
    }
    r, g, b, _ := c.RGBA()

    // These coefficients (the fractions 0.299, 0.587 and 0.114) are the same
    // as those given by the JFIF specification and used by func RGBToYCbCr in
    // ycbcr.go.
    //
    // Note that 19595 + 38470 + 7471 equals 65536.
    //
    // The 24 is 16 + 8. The 16 is the same as used in RGBToYCbCr. The 8 is
    // because the return value is 8 bit color, not 16 bit color.
    y := (19595*r + 38470*g + 7471*b + 1<<15) >> 24

    return Gray{uint8(y)}
}

Sur la base des faits ci-dessus, l'intensité Y est calculée avec la formule suivante:

Luminance: Y = 0,299 R + 0,587 G + 0,114 B

Si nous voulons appliquer différentes formules / algorithmes pour convertir une couleur en une intésité, par exemple

Moyenne: Y = ( R + G + B ) / 3
Luma: Y = 0,2126 R + 0,7152 G + 0,0722 B
Lustre: Y = (min ( R , G , B ) + max ( R , G , B )) / 2

Ensuite, les extraits suivants peuvent être utilisés.

// Converting image to grayscale
grayImg := image.NewGray(img.Bounds())
for y := img.Bounds().Min.Y; y < img.Bounds().Max.Y; y++ {
    for x := img.Bounds().Min.X; x < img.Bounds().Max.X; x++ {
        R, G, B, _ := img.At(x, y).RGBA()
        //Luma: Y = 0.2126*R + 0.7152*G + 0.0722*B
        Y := (0.2126*float64(R) + 0.7152*float64(G) + 0.0722*float64(B)) * (255.0 / 65535)
        grayPix := color.Gray{uint8(Y)}
        grayImg.Set(x, y, grayPix)
    }
}

Le calcul ci-dessus est effectué par multiplication en virgule flottante, et n'est certainement pas le plus efficace, mais il suffit pour démontrer l'idée. L'autre point est, lorsque vous appelez Set(x, y int, c color.Color) avec color.Gray comme troisième argument, le modèle de couleur n'effectuera pas la conversion de couleur comme on peut le voir dans la fonction grayModel précédente.



Modified text is an extract of the original Stack Overflow Documentation
Sous licence CC BY-SA 3.0
Non affilié à Stack Overflow