Skip to content

Commit 52e23df

Browse files
committed
Several stitcher updates
- Use different progress bar - Add bounds parameter to MedianBlendedImage - Add progress to MedianBlendedImage - Replace the `-lowram` flag with `-prerender` - Update README.md
1 parent d76dc20 commit 52e23df

File tree

7 files changed

+111
-42
lines changed

7 files changed

+111
-42
lines changed

.vscode/settings.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,20 @@
33
"Fullscreen",
44
"Lanczos",
55
"Vogel",
6+
"backbuffer",
7+
"cheggaaa",
8+
"downscaling",
69
"executables",
710
"gridify",
811
"hacky",
912
"hilbertify",
1013
"kbinani",
14+
"lowram",
1115
"manifoldco",
1216
"mapcap",
1317
"nfnt",
1418
"noita",
19+
"prerender",
1520
"schollz",
1621
"tcnksm",
1722
"xmax",

bin/stitch/README.md

Lines changed: 22 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,8 @@ example list of files:
2626

2727
## Usage
2828

29-
- Run the program and follow the interactive prompt.
30-
- Run the program with parameters:
29+
- Either run the program and follow the interactive prompt.
30+
- Or run the program with parameters:
3131
- `divide int`
3232
A downscaling factor. 2 will produce an image with half the side lengths. (default 1)
3333
- `input string`The source path of the image tiles to be stitched. (default "..\\..\\output")
@@ -41,22 +41,31 @@ example list of files:
4141
Lower bound of the output rectangle. This coordinate is not included in the output.
4242
- `ymin int`
4343
Upper bound of the output rectangle. This coordinate is included in the output.
44+
- `prerender`
45+
Pre renders the image in RAM before saving. Can speed things up if you have enough RAM.
4446

45-
Example of usage:
47+
To output the 100x100 area that is centered at the origin use:
4648

4749
``` Shell Session
48-
./stitch -divide 2
50+
./stitch -divide 1 -xmin -50 -xmax 50 -ymin -50 -ymax 50
4951
```
5052

51-
Example of output:
53+
To enter the parameters inside of the program:
5254

5355
``` Shell Session
54-
2019/10/25 16:02:25 Starting to read tile information at "..\..\output"
55-
2019/10/25 16:02:34 Got 43338 tiles
56-
2019/10/25 16:02:34 Total size of the possible output space is (-19968,-36864)-(21184,35100)
57-
2019/10/25 16:02:34 Creating output image with a size of (41152,71964)
58-
2019/10/25 16:02:46 Stitching 43338 tiles into an image at (-19968,-36864)-(21184,35100)
59-
100% |████████████████████████████████████████| [33m13s:0s]
60-
2019/10/25 16:35:59 Creating output file "output.png"
61-
2019/10/25 16:44:17 Created output file "output.png"
56+
./stitch
57+
```
58+
59+
Example output:
60+
61+
``` Shell Session
62+
Enter downscaling factor:1
63+
Enter input path:..\..\output
64+
2019/11/04 23:53:20 Starting to read tile information at "..\..\output"
65+
2019/11/04 23:53:32 Got 20933 tiles
66+
2019/11/04 23:53:32 Total size of the possible output space is (-25620,-36540)-(25620,36540)
67+
Enter output rectangle (xMin,yMin;xMax,yMax):-25620,-36540;25620,36540
68+
Enter output filename and path:output.png
69+
2019/11/04 23:53:35 Creating output file "output.png"
70+
105 / 571 [--------------->____________________________________________________________________] 18.39% 1 p/s ETA 14m0s
6271
```

bin/stitch/imagetiles.go

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import (
1616
"strconv"
1717
"sync"
1818

19-
"github.com/schollz/progressbar/v2"
19+
"github.com/cheggaaa/pb/v3"
2020
)
2121

2222
var regexFileParse = regexp.MustCompile(`^(-?\d+),(-?\d+).png$`)
@@ -82,7 +82,9 @@ func Stitch(tiles []imageTile, destImage *image.RGBA) error {
8282
}
8383
imgCopy := *img
8484
imgCopy.Rect = imgCopy.Rect.Add(tile.offset).Inset(4) // Reduce image bounds by 4 pixels on each side, because otherwise there will be artifacts.
85-
images = append(images, &imgCopy) // TODO: Fix transparent pixels at the output image border because of Inset
85+
images = append(images, &imgCopy)
86+
// TODO: Fix transparent pixels at the output image border because of inset
87+
// TODO: Fix downscaled images to cause artifacts because of the inset
8688
}
8789
}
8890

@@ -104,15 +106,16 @@ func Stitch(tiles []imageTile, destImage *image.RGBA) error {
104106

105107
// StitchGrid calls stitch, but divides the workload into a grid of chunks.
106108
// Additionally it runs the workload multithreaded.
107-
func StitchGrid(tiles []imageTile, destImage *image.RGBA, gridSize int) (errResult error) {
109+
func StitchGrid(tiles []imageTile, destImage *image.RGBA, gridSize int, bar *pb.ProgressBar) (errResult error) {
108110
//workloads := gridifyRectangle(destImage.Bounds(), gridSize)
109111
workloads, err := hilbertifyRectangle(destImage.Bounds(), gridSize)
110112
if err != nil {
111113
return err
112114
}
113115

114-
bar := progressbar.New(len(workloads))
115-
bar.RenderBlank()
116+
if bar != nil {
117+
bar.SetTotal(int64(len(workloads))).Start()
118+
}
116119

117120
// Start worker threads
118121
wc := make(chan image.Rectangle)
@@ -125,7 +128,9 @@ func StitchGrid(tiles []imageTile, destImage *image.RGBA, gridSize int) (errResu
125128
if err := Stitch(tiles, destImage.SubImage(workload).(*image.RGBA)); err != nil {
126129
errResult = err // This will not stop execution, but at least one of any errors is returned.
127130
}
128-
bar.Add(1)
131+
if bar != nil {
132+
bar.Increment()
133+
}
129134
}
130135
}()
131136
}
@@ -139,9 +144,6 @@ func StitchGrid(tiles []imageTile, destImage *image.RGBA, gridSize int) (errResu
139144
close(wc)
140145
wg.Wait()
141146

142-
// Newline because of the progress bar
143-
fmt.Println("")
144-
145147
return
146148
}
147149

bin/stitch/medianBlendedImage.go

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -18,23 +18,15 @@ type MedianBlendedImage struct {
1818
tiles []imageTile
1919
bounds image.Rectangle
2020

21-
cachedRow *image.RGBA
21+
cachedRow *image.RGBA
22+
queryCounter int
2223
}
2324

2425
// NewMedianBlendedImage creates a new image from several single image tiles.
25-
func NewMedianBlendedImage(tiles []imageTile) *MedianBlendedImage {
26-
totalBounds := image.Rectangle{}
27-
for i, tile := range tiles {
28-
if i == 0 {
29-
totalBounds = tile.Bounds()
30-
} else {
31-
totalBounds = totalBounds.Union(tile.Bounds())
32-
}
33-
}
34-
26+
func NewMedianBlendedImage(tiles []imageTile, bounds image.Rectangle) *MedianBlendedImage {
3527
return &MedianBlendedImage{
3628
tiles: tiles,
37-
bounds: totalBounds,
29+
bounds: bounds,
3830
cachedRow: &image.RGBA{},
3931
}
4032
}
@@ -56,6 +48,9 @@ func (mbi *MedianBlendedImage) Bounds() image.Rectangle {
5648
func (mbi *MedianBlendedImage) At(x, y int) color.Color {
5749
p := image.Point{x, y}
5850

51+
// Assume that every pixel is only queried once
52+
mbi.queryCounter++
53+
5954
if !p.In(mbi.cachedRow.Bounds()) {
6055
// Need to create a new row image
6156
rect := mbi.Bounds()
@@ -69,10 +64,17 @@ func (mbi *MedianBlendedImage) At(x, y int) color.Color {
6964
mbi.cachedRow = image.NewRGBA(rect)
7065

7166
// TODO: Don't use hilbert curve here
72-
if err := StitchGrid(mbi.tiles, mbi.cachedRow, 512); err != nil {
67+
if err := StitchGrid(mbi.tiles, mbi.cachedRow, 512, nil); err != nil {
7368
return color.RGBA{}
7469
}
7570
}
7671

7772
return mbi.cachedRow.RGBAAt(x, y)
7873
}
74+
75+
// Progress returns the approximate progress of any process that scans the image from top to bottom.
76+
func (mbi *MedianBlendedImage) Progress() (value, max int) {
77+
size := mbi.Bounds().Size()
78+
79+
return mbi.queryCounter, size.X * size.Y
80+
}

bin/stitch/stitch.go

Lines changed: 42 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,10 @@ import (
1313
"log"
1414
"os"
1515
"path/filepath"
16+
"sync"
17+
"time"
1618

19+
"github.com/cheggaaa/pb/v3"
1720
"github.com/manifoldco/promptui"
1821
)
1922

@@ -24,7 +27,7 @@ var flagXMin = flag.Int("xmin", 0, "Left bound of the output rectangle. This coo
2427
var flagYMin = flag.Int("ymin", 0, "Upper bound of the output rectangle. This coordinate is included in the output.")
2528
var flagXMax = flag.Int("xmax", 0, "Right bound of the output rectangle. This coordinate is not included in the output.")
2629
var flagYMax = flag.Int("ymax", 0, "Lower bound of the output rectangle. This coordinate is not included in the output.")
27-
var flagLowRAM = flag.Bool("lowram", true, "Reduces the needed ram drastically, at the expense of speed.")
30+
var flagPrerender = flag.Bool("prerender", false, "Pre renders the image in RAM before saving. Can speed things up if you have enough RAM.")
2831

2932
func main() {
3033
flag.Parse()
@@ -155,16 +158,44 @@ func main() {
155158
}
156159

157160
var outputImage image.Image
158-
if *flagLowRAM {
159-
outputImage = NewMedianBlendedImage(tiles)
160-
} else {
161+
bar := pb.Full.New(0)
162+
var wg sync.WaitGroup
163+
done := make(chan bool)
164+
165+
if *flagPrerender {
161166
log.Printf("Creating output image with a size of %v", outputRect.Size())
162167
tempImage := image.NewRGBA(outputRect)
163168

164-
log.Printf("Stitching %v tiles into an image at %v", len(tiles), outputImage.Bounds())
165-
if err := StitchGrid(tiles, tempImage, 512); err != nil {
169+
log.Printf("Stitching %v tiles into an image at %v", len(tiles), tempImage.Bounds())
170+
if err := StitchGrid(tiles, tempImage, 512, bar); err != nil {
166171
log.Panic(err)
167172
}
173+
bar.Finish()
174+
175+
outputImage = tempImage
176+
} else {
177+
tempImage := NewMedianBlendedImage(tiles, outputRect)
178+
_, max := tempImage.Progress()
179+
bar.SetTotal(int64(max)).Start().SetRefreshRate(1 * time.Second)
180+
181+
wg.Add(1)
182+
go func() {
183+
defer wg.Done()
184+
185+
ticker := time.NewTicker(1 * time.Second)
186+
for {
187+
select {
188+
case <-done:
189+
value, _ := tempImage.Progress()
190+
bar.SetCurrent(int64(value))
191+
bar.Finish()
192+
return
193+
case <-ticker.C:
194+
value, _ := tempImage.Progress()
195+
bar.SetCurrent(int64(value))
196+
}
197+
}
198+
}()
168199

169200
outputImage = tempImage
170201
}
@@ -180,6 +211,11 @@ func main() {
180211
log.Panic(err)
181212
}
182213

214+
if !*flagPrerender {
215+
done <- true
216+
wg.Wait()
217+
}
218+
183219
if err := f.Close(); err != nil {
184220
log.Panic(err)
185221
}

go.mod

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,14 @@ go 1.13
55
require (
66
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802 // indirect
77
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d // indirect
8+
github.com/cheggaaa/pb/v3 v3.0.2
89
github.com/gen2brain/shm v0.0.0-20180314170312-6c18ff7f8b90 // indirect
910
github.com/google/hilbert v0.0.0-20181122061418-320f2e35a565
1011
github.com/kbinani/screenshot v0.0.0-20190719135742-f06580e30cdc
1112
github.com/lxn/win v0.0.0-20190919090605-24c5960b03d8 // indirect
1213
github.com/manifoldco/promptui v0.3.2
1314
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646
14-
github.com/schollz/progressbar/v2 v2.14.0
15+
github.com/schollz/progressbar/v2 v2.14.0 // indirect
1516
github.com/tcnksm/go-input v0.0.0-20180404061846-548a7d7a8ee8 // indirect
1617
golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8
1718
gopkg.in/alecthomas/kingpin.v3-unstable v3.0.0-20180810215634-df19058c872c // indirect

go.sum

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,14 @@
11
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802 h1:1BDTz0u9nC3//pOCMdNH+CiXJVYJh5UQNCOBG7jbELc=
22
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
3+
github.com/VividCortex/ewma v1.1.1 h1:MnEK4VOv6n0RSY4vtRe3h11qjxL3+t0B8yOL8iMXdcM=
4+
github.com/VividCortex/ewma v1.1.1/go.mod h1:2Tkkvm3sRDVXaiyucHiACn4cqf7DpdyLvmxzcbUokwA=
35
github.com/alecthomas/gometalinter v2.0.11+incompatible h1:ENdXMllZNSVDTJUUVIzBW9CSEpntTrQa76iRsEFLX/M=
46
github.com/alecthomas/gometalinter v2.0.11+incompatible/go.mod h1:qfIpQGGz3d+NmgyPBqv+LSh50emm1pt72EtcX2vKYQk=
57
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d h1:UQZhZ2O0vMHr2cI+DC1Mbh0TJxzA3RcLoMsFw+aXw7E=
68
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=
9+
github.com/cheggaaa/pb v2.0.7+incompatible h1:gLKifR1UkZ/kLkda5gC0K6c8g+jU2sINPtBeOiNlMhU=
10+
github.com/cheggaaa/pb/v3 v3.0.2 h1:/u+zw5RBzW1CxRpVIqrZv4PpZpN+yaRPdsRORKyDjv4=
11+
github.com/cheggaaa/pb/v3 v3.0.2/go.mod h1:SqqeMF/pMOIu3xgGoxtPYhMNQP258xE4x/XRTYua+KU=
712
github.com/chzyer/logex v1.1.10 h1:Swpa1K6QvQznwJRcfTfQJmTE72DqScAa40E+fbHEXEE=
813
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
914
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e h1:fY5BOSpyZCqRo5OhCuC+XN+r/bBCmeuuJtjz+bCNIf8=
@@ -15,6 +20,8 @@ github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDk
1520
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
1621
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
1722
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
23+
github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys=
24+
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
1825
github.com/gen2brain/shm v0.0.0-20180314170312-6c18ff7f8b90 h1:QagTG5rauLt6pVVEhnVSrlIX4ifhVIZOwmw6x6D8TUw=
1926
github.com/gen2brain/shm v0.0.0-20180314170312-6c18ff7f8b90/go.mod h1:uF6rMu/1nvu+5DpiRLwusA6xB8zlkNoGzKn8lmYONUo=
2027
github.com/golang/lint v0.0.0-20181026193005-c67002cb31c3 h1:I4BOK3PBMjhWfQM2zPJKK7lOBGsrsvOB7kBELP33hiE=
@@ -42,8 +49,14 @@ github.com/manifoldco/promptui v0.3.2 h1:rir7oByTERac6jhpHUPErHuopoRDvO3jxS+Fdad
4249
github.com/manifoldco/promptui v0.3.2/go.mod h1:8JU+igZ+eeiiRku4T5BjtKh2ms8sziGpSYl1gN8Bazw=
4350
github.com/mattn/go-colorable v0.0.9 h1:UVL0vNpWh04HeJXV0KLcaT7r06gOH2l4OW6ddYRUIY4=
4451
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
52+
github.com/mattn/go-colorable v0.1.2 h1:/bC9yWikZXAL9uJdulbSfyVNIR3n3trXl+v8+1sx8mU=
53+
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
4554
github.com/mattn/go-isatty v0.0.4 h1:bnP0vzxcAdeI1zdubAl5PjU6zsERjGZb7raWodagDYs=
4655
github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
56+
github.com/mattn/go-isatty v0.0.8 h1:HLtExJ+uU2HOZ+wI0Tt5DtUDrx8yhUqDcp7fYERX4CE=
57+
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
58+
github.com/mattn/go-runewidth v0.0.4 h1:2BvfKmzob6Bmd4YsL0zygOqfdFnK7GR4QL06Do4/p7Y=
59+
github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
4760
github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db h1:62I3jR2EmQ4l5rM/4FEfDWcRD+abF5XlKShorW5LRoQ=
4861
github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db/go.mod h1:l0dey0ia/Uv7NcFFVbCLtqEBQbrT4OCwCSKTEv6enCw=
4962
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 h1:zYyBkD/k9seD2A7fsi6Oo2LfFZAehjjQMERAvZLEDnQ=
@@ -68,6 +81,7 @@ golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+o
6881
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3 h1:x/bBzNauLQAlE3fLku/xy92Y8QwKX5HZymrMz2IiKFc=
6982
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
7083
golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
84+
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
7185
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd h1:DBH9mDw0zluJT/R+nGuV3jWFWLFaHyYZWD4tOT+cjn0=
7286
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
7387
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=

0 commit comments

Comments
 (0)