最後活躍 1 month ago

JPSS "bowdetie" script

修訂 54104988e8e353831d4b4de6d90bc3a900ed31cf

bowdetie.go 原始檔案
1package main
2
3import (
4 "os"
5 "image"
6 "log"
7 "image/png"
8 "image/color"
9 "math"
10 "time"
11)
12
13//var filename = "JPSS1_VIIRS_I01_2017-12-20T07:54:34-02:00.png"
14var filename = "JPSS1_VIIRS_I01_2017-12-20T08:39:35-02:00.png"
15
16type Setting struct {
17 id int
18 name string
19 width int
20 params [6]int
21 params2 [6]int
22 bits int
23}
24
25type BowTie struct {
26 x0 int
27 y0 int
28 x1 int
29 y1 int
30}
31
32var settings = map[string]Setting {
33 "I01": {
34 id: 818,
35 name: "I01",
36 width: 6400,
37 params: [6]int{1280, 736, 1184, 1184, 736, 1280},
38 params2: [6]int{6, 2, 0, 0, 2, 6},
39 bits: 31,
40 },
41}
42
43func IsBlack(r,g,b uint32) bool {
44 return r == 0 && g == 0 && b == 0
45}
46
47func BilinearInterp(x, y float32, q0, q1, q2, q3 uint32) uint16 {
48 rx := int(math.Floor(float64(x)))
49 ry := int(math.Floor(float64(y)))
50 fracX := float64(x) - float64(rx)
51 fracY := float64(y) - float64(ry)
52 invFracX := 1 - fracX
53 invFracY := 1 - fracY
54
55 q0f := float64(q0)
56 q1f := float64(q1)
57 q2f := float64(q2)
58 q3f := float64(q3)
59
60 val := (q0f * invFracX + q1f * fracX + q2f * invFracY + q3f * fracY) / 2
61
62 return uint16(val)
63}
64
65func LinearInterp(r float32, q0, q1 uint32) uint16 {
66 return uint16(float32(q0) * r + float32(q1) * (1 - r))
67}
68
69func CosineInterp(r float32, q0, q1 uint32) uint16 {
70 var mu = float64(r)
71 var mu2 = (1 - math.Cos(mu * math.Pi)) / 2
72
73 return uint16(float64(q0) * (1 - mu2) + float64(q1) * (mu2))
74}
75
76var numPasses = 4
77
78func ProcessBowTie(m image.Image, bt BowTie) {
79 var gm = m.(*image.Gray16)
80 var h = float32(bt.y1 - bt.y0)
81 for x := bt.x0; x < bt.x1; x++ {
82 var q0, _, _, _ = m.At(x, bt.y0 - 1).RGBA()
83 var q1, _, _, _ = m.At(x, bt.y1 + 1).RGBA()
84 for y := bt.y0; y < bt.y1; y++ {
85 // Linear / Cosine
86 var r = float32(y - bt.y0) / float32(h)
87 gm.Set(x, y, color.Gray16{ Y: LinearInterp(r, q0, q1) })
88 }
89 }
90 for i := 0; i < numPasses; i++ {
91 for x := bt.x0; x < bt.x1; x++ {
92 for y := bt.y0; y < bt.y1; y++ {
93 var q2, _, _, _= m.At(x, y).RGBA()
94 var q3, _, _, _= m.At(x+1, y).RGBA()
95 gm.Set(x, y, color.Gray16{Y: LinearInterp(0.5, q2, q3)})
96 }
97 }
98 }
99}
100
101func main() {
102 reader, err := os.Open(filename)
103 if err != nil {
104 panic(err)
105 }
106
107 m, format, err := image.Decode(reader)
108
109 if err != nil {
110 panic(err)
111 }
112
113 log.Println("Found image format", format)
114
115 reader.Close()
116
117 var currSetting = settings["I01"]
118 var bowTies []BowTie
119
120 bounds := m.Bounds()
121
122 startTime := time.Now()
123
124 // Find head bowtie
125 var x = bounds.Min.X
126 for z := 0; z < 6; z++ {
127 if z == 2 || z == 3 {
128 x += currSetting.params[z]
129 continue
130 }
131 var csw = currSetting.params[z]
132 var csh = currSetting.params2[z]
133 for y := bounds.Min.Y; y < bounds.Max.Y; y++ {
134 r, g, b, _ := m.At(x, y).RGBA()
135 if IsBlack(r, g, b) {
136 //log.Println("Found black pixel at", y)
137 var nextY = y + csh
138 if nextY > bounds.Max.Y || nextY + 1 > bounds.Max.Y {
139 break
140 }
141 nr, ng, nb, _ := m.At(x, nextY).RGBA()
142 n2r, n2g, n2b, _ := m.At(x, nextY + 1).RGBA()
143 if IsBlack(nr, ng, nb) && !IsBlack(n2r, n2g, n2b) {
144 bt := BowTie{
145 x0: x,
146 y0: y,
147 x1: x + csw + 1,
148 y1: y + csh + 1,
149 }
150 bowTies = append(bowTies, bt)
151 y += currSetting.params2[0]
152 }
153 }
154 }
155 x += currSetting.params[z]
156 }
157
158 // Fill Bow Ties with red
159 for i := 0; i < len(bowTies); i++ {
160 //log.Println("Paiting bowtie", i)
161 ProcessBowTie(m, bowTies[i])
162 }
163
164 delta := time.Now().Sub(startTime).Seconds()
165
166 log.Println("Took", delta, "seconds to debowtie!")
167
168 out, err := os.Create("out.png")
169 err = png.Encode(out, m)
170 if err != nil {
171 panic(err)
172 }
173 out.Close()
174}