-
Notifications
You must be signed in to change notification settings - Fork 6
/
Copy pathimage.go
152 lines (126 loc) · 3.5 KB
/
image.go
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
package gocarina
import (
"image"
"image/color"
"image/draw"
"math"
"math/rand"
)
// BoundingBox returns the minimum rectangle containing all non-white pixels in the source image.
func BoundingBox(src image.Image, border int) image.Rectangle {
min := src.Bounds().Min
max := src.Bounds().Max
leftX := func() int {
for x := min.X; x < max.X; x++ {
for y := min.Y; y < max.Y; y++ {
c := src.At(x, y)
if IsBlack(c) {
return x - border
}
}
}
// no non-white pixels found
return min.X
}
rightX := func() int {
for x := max.X - 1; x >= min.X; x-- {
for y := min.Y; y < max.Y; y++ {
c := src.At(x, y)
if IsBlack(c) {
return x + border
}
}
}
// no non-white pixels found
return max.X
}
topY := func() int {
for y := min.Y; y < max.Y; y++ {
for x := min.X; x < max.X; x++ {
c := src.At(x, y)
if IsBlack(c) {
return y - border
}
}
}
// no non-white pixels found
return max.Y
}
bottomY := func() int {
for y := max.Y - 1; y >= min.Y; y-- {
for x := min.X; x < max.X; x++ {
c := src.At(x, y)
if IsBlack(c) {
return y + border
}
}
}
// no non-white pixels found
return max.Y
}
// TODO: decide if +1 is correct or not
return image.Rect(leftX(), topY(), rightX()+1, bottomY()+1)
}
// Scale scales the src image to the given rectangle using Nearest Neighbor
func Scale(src image.Image, r image.Rectangle) image.Image {
dst := image.NewRGBA(r)
sb := src.Bounds()
db := dst.Bounds()
for y := db.Min.Y; y < db.Max.Y; y++ {
percentDownDest := float64(y) / float64(db.Dy())
for x := db.Min.X; x < db.Max.X; x++ {
percentAcrossDest := float64(x) / float64(db.Dx())
srcX := int(math.Floor(percentAcrossDest * float64(sb.Dx())))
srcY := int(math.Floor(percentDownDest * float64(sb.Dy())))
pix := src.At(sb.Min.X+srcX, sb.Min.Y+srcY)
dst.Set(x, y, pix)
}
}
return dst
}
// NoiseImage randomly alters the pixels of the given image.
// Originally this used randomColor(), but that result in some black pixels, which totally defeats the
// bounding box algorithm. A better BBox algorithm would be nice...
func AddNoise(img *image.RGBA) {
for row := img.Bounds().Min.Y; row < img.Bounds().Max.Y; row++ {
for col := img.Bounds().Min.X; col < img.Bounds().Max.X; col++ {
if rand.Float64() > 0.90 {
//img.Set(col, row, randomColor())
img.Set(col, row, color.White)
}
}
}
}
// from http://blog.golang.org/go-imagedraw-package ("Converting an Image to RGBA"),
// modified slightly to be a no-op if the src image is already RGBA
//
func ConvertToRGBA(img image.Image) (result *image.RGBA) {
result, ok := img.(*image.RGBA)
if ok {
return result
}
b := img.Bounds()
result = image.NewRGBA(image.Rect(0, 0, b.Dx(), b.Dy()))
draw.Draw(result, result.Bounds(), img, b.Min, draw.Src)
return
}
// randomColor returns a color with completely random values for RGBA.
func randomColor() color.Color {
// start with non-premultiplied RGBA
c := color.NRGBA{R: uint8(rand.Intn(256)), G: uint8(rand.Intn(256)), B: uint8(rand.Intn(256)), A: uint8(rand.Intn(256))}
return color.RGBAModel.Convert(c)
}
// ImageToString returns a textual approximation of a black & white image for debugging purposes.
func ImageToString(img image.Image) (result string) {
for row := img.Bounds().Min.Y; row < img.Bounds().Max.Y; row++ {
for col := img.Bounds().Min.X; col < img.Bounds().Max.X; col++ {
if IsBlack(img.At(col, row)) {
result += "."
} else {
result += "O"
}
}
result += "\n"
}
return
}