Lucas Teske revised this gist 7 years ago. Go to revision
1 file changed, 36 insertions, 36 deletions
bowdetie.go
| @@ -5,9 +5,9 @@ import ( | |||
| 5 | 5 | "image" | |
| 6 | 6 | "log" | |
| 7 | 7 | "image/png" | |
| 8 | - | "image/color" | |
| 9 | 8 | "math" | |
| 10 | 9 | "time" | |
| 10 | + | "github.com/nfnt/resize" | |
| 11 | 11 | ) | |
| 12 | 12 | ||
| 13 | 13 | //var filename = "JPSS1_VIIRS_I01_2017-12-20T07:54:34-02:00.png" | |
| @@ -44,26 +44,8 @@ func IsBlack(r,g,b uint32) bool { | |||
| 44 | 44 | return r == 0 && g == 0 && b == 0 | |
| 45 | 45 | } | |
| 46 | 46 | ||
| 47 | - | func 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 | - | ||
| 65 | 47 | func LinearInterp(r float32, q0, q1 uint32) uint16 { | |
| 66 | - | return uint16(float32(q0) * r + float32(q1) * (1 - r)) | |
| 48 | + | return uint16(float32(q0) * (1 - r) + float32(q1) * (r)) | |
| 67 | 49 | } | |
| 68 | 50 | ||
| 69 | 51 | func CosineInterp(r float32, q0, q1 uint32) uint16 { | |
| @@ -77,25 +59,43 @@ var numPasses = 4 | |||
| 77 | 59 | ||
| 78 | 60 | func ProcessBowTie(m image.Image, bt BowTie) { | |
| 79 | 61 | 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 | - | } | |
| 62 | + | var w = bt.x1 - bt.x0 | |
| 63 | + | var h = bt.y1 - bt.y0 | |
| 64 | + | var btImg = image.NewGray16(image.Rect(0, 0, w, 2)) | |
| 65 | + | // Slice Two lines | |
| 66 | + | for x := 0; x < w; x++ { | |
| 67 | + | btImg.Set(x, 0, gm.At(bt.x0 + x, bt.y0 - 1)) | |
| 68 | + | btImg.Set(x, 1, gm.At(bt.x0 + x, bt.y1 + 1)) | |
| 89 | 69 | } | |
| 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 | - | } | |
| 70 | + | ||
| 71 | + | btImgRes := resize.Resize(uint(float32(w)), uint(h) , btImg, resize.Lanczos3) | |
| 72 | + | ||
| 73 | + | for x := 0; x < w; x++ { | |
| 74 | + | for y := 0; y < h; y++ { | |
| 75 | + | gm.Set(bt.x0 + x, bt.y0 + y, btImgRes.At(x, y)) | |
| 97 | 76 | } | |
| 98 | 77 | } | |
| 78 | + | ||
| 79 | + | //var gm = m.(*image.Gray16) | |
| 80 | + | //var h = float32(bt.y1 - bt.y0) + 2 | |
| 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 | 99 | } | |
| 100 | 100 | ||
| 101 | 101 | func main() { | |
Lucas Teske revised this gist 7 years ago. Go to revision
1 file changed, 174 insertions
bowdetie.go(file created)
| @@ -0,0 +1,174 @@ | |||
| 1 | + | package main | |
| 2 | + | ||
| 3 | + | import ( | |
| 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" | |
| 14 | + | var filename = "JPSS1_VIIRS_I01_2017-12-20T08:39:35-02:00.png" | |
| 15 | + | ||
| 16 | + | type Setting struct { | |
| 17 | + | id int | |
| 18 | + | name string | |
| 19 | + | width int | |
| 20 | + | params [6]int | |
| 21 | + | params2 [6]int | |
| 22 | + | bits int | |
| 23 | + | } | |
| 24 | + | ||
| 25 | + | type BowTie struct { | |
| 26 | + | x0 int | |
| 27 | + | y0 int | |
| 28 | + | x1 int | |
| 29 | + | y1 int | |
| 30 | + | } | |
| 31 | + | ||
| 32 | + | var 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 | + | ||
| 43 | + | func IsBlack(r,g,b uint32) bool { | |
| 44 | + | return r == 0 && g == 0 && b == 0 | |
| 45 | + | } | |
| 46 | + | ||
| 47 | + | func 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 | + | ||
| 65 | + | func LinearInterp(r float32, q0, q1 uint32) uint16 { | |
| 66 | + | return uint16(float32(q0) * r + float32(q1) * (1 - r)) | |
| 67 | + | } | |
| 68 | + | ||
| 69 | + | func 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 | + | ||
| 76 | + | var numPasses = 4 | |
| 77 | + | ||
| 78 | + | func 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 | + | ||
| 101 | + | func 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 | + | } | |