mirror of
https://github.com/golang/go
synced 2024-11-18 08:04:40 -07:00
image/color: tweak the formula for converting to gray.
This makes grayModel and gray16Model in color.go use the exact same formula as RGBToYCbCr in ycbcr.go. They were the same formula in theory, but in practice the color.go versions used a divide by 1000 and the ycbcr.go versions used a (presumably faster) shift by 16. This implies the nice property that converting an image.RGBA to an image.YCbCr and then taking only the Y channel is equivalent to converting an image.RGBA directly to an image.Gray. The difference between the two formulae is non-zero, but small: https://play.golang.org/p/qG7oe-eqHI Updates #16251 Change-Id: I288ecb957fd6eceb9626410bd1a8084d2e4f8198 Reviewed-on: https://go-review.googlesource.com/31538 Reviewed-by: Rob Pike <r@golang.org>
This commit is contained in:
parent
a190f3c8a3
commit
584e3ea258
@ -246,8 +246,18 @@ func grayModel(c Color) Color {
|
|||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
r, g, b, _ := c.RGBA()
|
r, g, b, _ := c.RGBA()
|
||||||
y := (299*r + 587*g + 114*b + 500) / 1000
|
|
||||||
return Gray{uint8(y >> 8)}
|
// 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)}
|
||||||
}
|
}
|
||||||
|
|
||||||
func gray16Model(c Color) Color {
|
func gray16Model(c Color) Color {
|
||||||
@ -255,7 +265,14 @@ func gray16Model(c Color) Color {
|
|||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
r, g, b, _ := c.RGBA()
|
r, g, b, _ := c.RGBA()
|
||||||
y := (299*r + 587*g + 114*b + 500) / 1000
|
|
||||||
|
// 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.
|
||||||
|
y := (19595*r + 38470*g + 7471*b + 1<<15) >> 16
|
||||||
|
|
||||||
return Gray16{uint16(y)}
|
return Gray16{uint16(y)}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,6 +17,8 @@ func RGBToYCbCr(r, g, b uint8) (uint8, uint8, uint8) {
|
|||||||
b1 := int32(b)
|
b1 := int32(b)
|
||||||
|
|
||||||
// yy is in range [0,0xff].
|
// yy is in range [0,0xff].
|
||||||
|
//
|
||||||
|
// Note that 19595 + 38470 + 7471 equals 65536.
|
||||||
yy := (19595*r1 + 38470*g1 + 7471*b1 + 1<<15) >> 16
|
yy := (19595*r1 + 38470*g1 + 7471*b1 + 1<<15) >> 16
|
||||||
|
|
||||||
// The bit twiddling below is equivalent to
|
// The bit twiddling below is equivalent to
|
||||||
@ -32,6 +34,8 @@ func RGBToYCbCr(r, g, b uint8) (uint8, uint8, uint8) {
|
|||||||
// Note that the uint8 type conversion in the return
|
// Note that the uint8 type conversion in the return
|
||||||
// statement will convert ^int32(0) to 0xff.
|
// statement will convert ^int32(0) to 0xff.
|
||||||
// The code below to compute cr uses a similar pattern.
|
// The code below to compute cr uses a similar pattern.
|
||||||
|
//
|
||||||
|
// Note that -11056 - 21712 + 32768 equals 0.
|
||||||
cb := -11056*r1 - 21712*g1 + 32768*b1 + 257<<15
|
cb := -11056*r1 - 21712*g1 + 32768*b1 + 257<<15
|
||||||
if uint32(cb)&0xff000000 == 0 {
|
if uint32(cb)&0xff000000 == 0 {
|
||||||
cb >>= 16
|
cb >>= 16
|
||||||
@ -39,6 +43,7 @@ func RGBToYCbCr(r, g, b uint8) (uint8, uint8, uint8) {
|
|||||||
cb = ^(cb >> 31)
|
cb = ^(cb >> 31)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Note that 32768 - 27440 - 5328 equals 0.
|
||||||
cr := 32768*r1 - 27440*g1 - 5328*b1 + 257<<15
|
cr := 32768*r1 - 27440*g1 - 5328*b1 + 257<<15
|
||||||
if uint32(cr)&0xff000000 == 0 {
|
if uint32(cr)&0xff000000 == 0 {
|
||||||
cr >>= 16
|
cr >>= 16
|
||||||
|
Loading…
Reference in New Issue
Block a user