1. 程式人生 > >The Go image package

The Go image package

21 September 2011

Introduction

The image and image/color packages define a number of types: color.Color and color.Model describe colors, image.Point and image.Rectangle describe basic 2-D geometry, and image.Image brings the two concepts together to represent a rectangular grid of colors. A

separate article covers image composition with the image/draw package.

Colors and Color Models

Color is an interface that defines the minimal method set of any type that can be considered a color: one that can be converted to red, green, blue and alpha values. The conversion may be lossy, such as converting from CMYK or YCbCr color spaces.

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.
    RGBA() (r, g, b, a uint32)
}

There are three important subtleties about the return values. First, the red, green and blue are alpha-premultiplied: a fully saturated red that is also 25% transparent is represented by RGBA returning a 75% r. Second, the channels have a 16-bit effective range: 100% red is represented by RGBA returning an r of 65535, not 255, so that converting from CMYK or YCbCr is not as lossy. Third, the type returned is uint32, even though the maximum value is 65535, to guarantee that multiplying two values together won't overflow. Such multiplications occur when blending two colors according to an alpha mask from a third color, in the style of Porter and Duff's classic algebra:

dstr, dstg, dstb, dsta := dst.RGBA()
srcr, srcg, srcb, srca := src.RGBA()
_, _, _, m := mask.RGBA()
const M = 1<<16 - 1
// The resultant red value is a blend of dstr and srcr, and ranges in [0, M].
// The calculation for green, blue and alpha is similar.
dstr = (dstr*(M-m) + srcr*m) / M

The last line of that code snippet would have been more complicated if we worked with non-alpha-premultiplied colors, which is why Color uses alpha-premultiplied values.

The image/color package also defines a number of concrete types that implement the Color interface. For example, RGBA is a struct that represents the classic "8 bits per channel" color.

type RGBA struct {
    R, G, B, A uint8
}

Note that the R field of an RGBA is an 8-bit alpha-premultiplied color in the range [0, 255]. RGBA satisfies the Color interface by multiplying that value by 0x101 to generate a 16-bit alpha-premultiplied color in the range [0, 65535]. Similarly, the NRGBA struct type represents an 8-bit non-alpha-premultiplied color, as used by the PNG image format. When manipulating an NRGBA's fields directly, the values are non-alpha-premultiplied, but when calling the RGBA method, the return values are alpha-premultiplied.

A Model is simply something that can convert `Color`s to other `Color`s, possibly lossily. For example, the GrayModel can convert any Color to a desaturated Gray. A Palette can convert any Color to one from a limited palette.

type Model interface {
    Convert(c Color) Color
}

type Palette []Color

Points and Rectangles

A Point is an (x, y) co-ordinate on the integer grid, with axes increasing right and down. It is neither a pixel nor a grid square. A Point has no intrinsic width, height or color, but the visualizations below use a small colored square.

type Point struct {
    X, Y int
}
p := image.Point{2, 1}

A Rectangle is an axis-aligned rectangle on the integer grid, defined by its top-left and bottom-right Point. A Rectangle also has no intrinsic color, but the visualizations below outline rectangles with a thin colored line, and call out their Min and Max `Point`s.

type Rectangle struct {
    Min, Max Point
}

For convenience, image.Rect(x0, y0, x1, y1) is equivalent to image.Rectangle{image.Point{x0, y0}, image.Point{x1, y1}}, but is much easier to type.

A Rectangle is inclusive at the top-left and exclusive at the bottom-right. For a Point p and a Rectangle r, p.In(r) if and only if r.Min.X <= p.X && p.X < r.Max.X, and similarly for Y. This is analogous to how a slice s[i0:i1] is inclusive at the low end and exclusive at the high end. (Unlike arrays and slices, a Rectangle often has a non-zero origin.)

r := image.Rect(2, 1, 5, 5)
// Dx and Dy return a rectangle's width and height.
fmt.Println(r.Dx(), r.Dy(), image.Pt(0, 0).In(r)) // prints 3 4 false

Adding a Point to a Rectangle translates the Rectangle. Points and Rectangles are not restricted to be in the bottom-right quadrant.

r := image.Rect(2, 1, 5, 5).Add(image.Pt(-4, -2))
fmt.Println(r.Dx(), r.Dy(), image.Pt(0, 0).In(r)) // prints 3 4 true

Intersecting two Rectangles yields another Rectangle, which may be empty.

r := image.Rect(0, 0, 4, 3).Intersect(image.Rect(2, 2, 5, 5))
// Size returns a rectangle's width and height, as a Point.
fmt.Printf("%#v\n", r.Size()) // prints image.Point{X:2, Y:1}

Points and Rectangles are passed and returned by value. A function that takes a Rectangle argument will be as efficient as a function that takes two Point arguments, or four int arguments.

Images

An Image maps every grid square in a Rectangle to a Color from a Model. "The pixel at (x, y)" refers to the color of the grid square defined by the points (x, y), (x+1, y), (x+1, y+1) and (x, y+1).

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
}

A common mistake is assuming that an Image's bounds start at (0, 0). For example, an animated GIF contains a sequence of Images, and each Image after the first typically only holds pixel data for the area that changed, and that area doesn't necessarily start at (0, 0). The correct way to iterate over an Image m's pixels looks like:

b := m.Bounds()
for y := b.Min.Y; y < b.Max.Y; y++ {
 for x := b.Min.X; x < b.Max.X; x++ {
  doStuffWith(m.At(x, y))
 }
}

Image implementations do not have to be based on an in-memory slice of pixel data. For example, a Uniform is an Image of enormous bounds and uniform color, whose in-memory representation is simply that color.

type Uniform struct {
    C color.Color
}

Typically, though, programs will want an image based on a slice. Struct types like RGBA and Gray (which other packages refer to as image.RGBA and image.Gray) hold slices of pixel data and implement the Image interface.

type RGBA struct {
    // Pix holds the image's pixels, in R, G, B, A order. The pixel at
    // (x, y) starts at Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)*4].
    Pix []uint8
    // Stride is the Pix stride (in bytes) between vertically adjacent pixels.
    Stride int
    // Rect is the image's bounds.
    Rect Rectangle
}

These types also provide a Set(x, y int, c color.Color) method that allows modifying the image one pixel at a time.

m := image.NewRGBA(image.Rect(0, 0, 640, 480))
m.Set(5, 5, color.RGBA{255, 0, 0, 255})

If you're reading or writing a lot of pixel data, it can be more efficient, but more complicated, to access these struct type's Pix field directly.

The slice-based Image implementations also provide a SubImage method, which returns an Image backed by the same array. Modifying the pixels of a sub-image will affect the pixels of the original image, analogous to how modifying the contents of a sub-slice s[i0:i1] will affect the contents of the original slice s.

m0 := image.NewRGBA(image.Rect(0, 0, 8, 5))
m1 := m0.SubImage(image.Rect(1, 2, 5, 5)).(*image.RGBA)
fmt.Println(m0.Bounds().Dx(), m1.Bounds().Dx()) // prints 8, 4
fmt.Println(m0.Stride == m1.Stride)             // prints true

For low-level code that works on an image's Pix field, be aware that ranging over Pix can affect pixels outside an image's bounds. In the example above, the pixels covered by m1.Pix are shaded in blue. Higher-level code, such as the At and Set methods or the image/draw package, will clip their operations to the image's bounds.

Image Formats

The standard package library supports a number of common image formats, such as GIF, JPEG and PNG. If you know the format of a source image file, you can decode from an io.Reader directly.

import (
 "image/jpeg"
 "image/png"
 "io"
)

// convertJPEGToPNG converts from JPEG to PNG.
func convertJPEGToPNG(w io.Writer, r io.Reader) error {
 img, err := jpeg.Decode(r)
 if err != nil {
  return err
 }
 return png.Encode(w, img)
}

If you have image data of unknown format, the image.Decode function can detect the format. The set of recognized formats is constructed at run time and is not limited to those in the standard package library. An image format package typically registers its format in an init function, and the main package will "underscore import" such a package solely for the side effect of format registration.

import (
 "image"
 "image/png"
 "io"

 _ "code.google.com/p/vp8-go/webp"
 _ "image/jpeg"
)

// convertToPNG converts from any recognized format to PNG.
func convertToPNG(w io.Writer, r io.Reader) error {
 img, _, err := image.Decode(r)
 if err != nil {
  return err
 }
 return png.Encode(w, img)
}

相關推薦

The Go image package

21 September 2011 Introduction The image and image/color packages define a number of types: color.Color and colo

The Go image/draw package

29 September 2011 Introduction Package image/draw defines only one operation: drawing a source image onto a dest

Gopackage

變量 com 需要 var 報錯 color org .com 進行 一、包的一些基本的概念 1、在同一個目錄下的所有go文件中,只能有一個main函數。如果存在多個main函數,則在編譯的時候會報錯 那麽,在同一個目錄下的兩個go文件究竟是什麽關系? 為什麽會

win10 安裝nodejs,報錯there is a problem in the windows installer package

nload 裝包 ack next org get 就是 技術分享 提示符 1. 在開始面板找到命令提示符,右鍵選擇“以管理員身份運行” 2. 進入到安裝包的文件目錄內 3. 回到命令提示符窗口,運行安裝包名字 之後會跳出安裝提示,點擊運行 之後就一直next,就

No module named _tkinter, please install the python-tk package 解決方法總結

not 原因 sin 程序開發 找到 pytho iss 配置 重新   0. 前言   在ipython環境中,要用到matlotlib庫,運行.py文件時,提示以下錯誤:   No module named _tkinter, please install the py

go 學習 ---package

1、包簡述   GO本身沒有專案的概念,只有包,包括可執行包和不可執行包,而不管什麼包,都應該包含在 $GOPATH/src 目錄下,GO命令和編譯器會在 $GOPATH/src 目錄下搜尋相應的包。比如 import "logging" 則會在所有設定的 $GOPATH/src 下去尋

問題:(機器學習)ImportError: No module named '_tkinter', please install the python3-tk package

在機器學習的過程中遇到問題: 安裝 sudo apt install python3-tk (Ubuntu) yum install python3-tk (Centos) 測試 如果沒奏效,繼續下一步 sudo apt install tk-dev (Ubuntu/Deb

Research Report on the Optical Image Stabilization

電子科技大學 格拉斯哥學院 2017/2018級 席文正 Introduction Image stabilization is the technique of improving image quality by actively removing the apparent mo

Go語言開發者福利 - 國內版 The Go Playground

本文為原創文章,轉載註明出處,歡迎掃碼關注公眾號flysnow_org或者網站www.flysnow.org/,第一時間看後續精彩文章。覺得好的話,順手分享到朋友圈吧,感謝支援。 作為Go語言開發者,我們都知道,Golang為我們提供了一個線上的、可以執行Go語言程式碼的、可以分享Go語言程式碼的

ImportError: No module named '_tkinter', please install the python3-tk package

解決: 進入專案所在的虛擬環境中,安裝python3-tk包 cd /home/dorothy/ZX/myproject/p3/bin source ./active #進入虛擬環境 sudo ap

Chapter 8:Automating the Featurizer: Image Feature Extraction and Deep Learning

一、the simplest image features 最簡單的image表徵方法為:pixel matrix。但是,這種表徵方法,沒有將pixel之間的relationship囊括在內,因此,無法capture enough semantic inform

關於linux(CentOS)無法更新安裝軟體出錯的解決辦法(提示The program package-cleanup is found in the yum-utils package

關於使用yum“The program package-cleanup is...”的解決辦法 在使用yum 時總是有提示資訊:  The program package-cleanup is found in the yum-utils package.    www.

How to Enable the GD Image Library for WordPress?

很久以前還在用 php5 + wordpress 時,文章的縮圖都有自動被產生,某一次升級之後,縮圖功能就不見了。花了2小時Google 終於找到原因。 解法如下: apt-get install php7.0-gd phpenmod gd /etc/init.d/php7.0-fpm restart p

How can i detect the library image is from front camera or back camera

遇到一個奇怪的問題,iOS 前鏡頭拍的照片,被旋轉了 180度。 解法如下: Your code checks for available cameras on the device. What you need to do is read the metadata for the image after

The Go init Function

There are times, when creating applications in Go, that you need to be able to set up some form of state on the initial startup of your program. Th

Become a Better R Programmer with the Awesome ‘lobstr’ Package

“Tools amplify your talent. The better your tools, and the better you know how to use them, the more productive you can be.” — Andrew Hunt, The Pragmatic P

How the Go runtime implements maps efficiently (without generics)

This post discusses how maps are implemented in Go. It is based on a presentation I gave at the GoCon Spring 2018 conference in Tokyo, Japan. What is a

If aligned memory writes are atomic, why do we need the sync/atomic package?

This is a post inspired by a question on the Go Forum. The question, paraphrased, was “If properly aligned writes are guaranteed to be atomic by the pr

Updating the Go Code of Conduct

23 May 2018 In November 2015, we introduced the Go Code of Conduct. It was developed in a collaboratio

The empty interface in the Go programming language

One of the most hotly debated topics in the world of the Go programming language, is the lack of generics. Generics are considered a key feature in othe