mirror of
https://github.com/Dadido3/noita-mapcap.git
synced 2024-12-22 02:17:33 +00:00
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
This commit is contained in:
parent
d76dc20936
commit
52e23df1ee
5
.vscode/settings.json
vendored
5
.vscode/settings.json
vendored
@ -3,15 +3,20 @@
|
||||
"Fullscreen",
|
||||
"Lanczos",
|
||||
"Vogel",
|
||||
"backbuffer",
|
||||
"cheggaaa",
|
||||
"downscaling",
|
||||
"executables",
|
||||
"gridify",
|
||||
"hacky",
|
||||
"hilbertify",
|
||||
"kbinani",
|
||||
"lowram",
|
||||
"manifoldco",
|
||||
"mapcap",
|
||||
"nfnt",
|
||||
"noita",
|
||||
"prerender",
|
||||
"schollz",
|
||||
"tcnksm",
|
||||
"xmax",
|
||||
|
@ -26,8 +26,8 @@ example list of files:
|
||||
|
||||
## Usage
|
||||
|
||||
- Run the program and follow the interactive prompt.
|
||||
- Run the program with parameters:
|
||||
- Either run the program and follow the interactive prompt.
|
||||
- Or run the program with parameters:
|
||||
- `divide int`
|
||||
A downscaling factor. 2 will produce an image with half the side lengths. (default 1)
|
||||
- `input string`The source path of the image tiles to be stitched. (default "..\\..\\output")
|
||||
@ -41,22 +41,31 @@ example list of files:
|
||||
Lower bound of the output rectangle. This coordinate is not included in the output.
|
||||
- `ymin int`
|
||||
Upper bound of the output rectangle. This coordinate is included in the output.
|
||||
- `prerender`
|
||||
Pre renders the image in RAM before saving. Can speed things up if you have enough RAM.
|
||||
|
||||
Example of usage:
|
||||
To output the 100x100 area that is centered at the origin use:
|
||||
|
||||
``` Shell Session
|
||||
./stitch -divide 2
|
||||
./stitch -divide 1 -xmin -50 -xmax 50 -ymin -50 -ymax 50
|
||||
```
|
||||
|
||||
Example of output:
|
||||
To enter the parameters inside of the program:
|
||||
|
||||
``` Shell Session
|
||||
2019/10/25 16:02:25 Starting to read tile information at "..\..\output"
|
||||
2019/10/25 16:02:34 Got 43338 tiles
|
||||
2019/10/25 16:02:34 Total size of the possible output space is (-19968,-36864)-(21184,35100)
|
||||
2019/10/25 16:02:34 Creating output image with a size of (41152,71964)
|
||||
2019/10/25 16:02:46 Stitching 43338 tiles into an image at (-19968,-36864)-(21184,35100)
|
||||
100% |████████████████████████████████████████| [33m13s:0s]
|
||||
2019/10/25 16:35:59 Creating output file "output.png"
|
||||
2019/10/25 16:44:17 Created output file "output.png"
|
||||
./stitch
|
||||
```
|
||||
|
||||
Example output:
|
||||
|
||||
``` Shell Session
|
||||
Enter downscaling factor:1
|
||||
Enter input path:..\..\output
|
||||
2019/11/04 23:53:20 Starting to read tile information at "..\..\output"
|
||||
2019/11/04 23:53:32 Got 20933 tiles
|
||||
2019/11/04 23:53:32 Total size of the possible output space is (-25620,-36540)-(25620,36540)
|
||||
Enter output rectangle (xMin,yMin;xMax,yMax):-25620,-36540;25620,36540
|
||||
Enter output filename and path:output.png
|
||||
2019/11/04 23:53:35 Creating output file "output.png"
|
||||
105 / 571 [--------------->____________________________________________________________________] 18.39% 1 p/s ETA 14m0s
|
||||
```
|
||||
|
@ -16,7 +16,7 @@ import (
|
||||
"strconv"
|
||||
"sync"
|
||||
|
||||
"github.com/schollz/progressbar/v2"
|
||||
"github.com/cheggaaa/pb/v3"
|
||||
)
|
||||
|
||||
var regexFileParse = regexp.MustCompile(`^(-?\d+),(-?\d+).png$`)
|
||||
@ -82,7 +82,9 @@ func Stitch(tiles []imageTile, destImage *image.RGBA) error {
|
||||
}
|
||||
imgCopy := *img
|
||||
imgCopy.Rect = imgCopy.Rect.Add(tile.offset).Inset(4) // Reduce image bounds by 4 pixels on each side, because otherwise there will be artifacts.
|
||||
images = append(images, &imgCopy) // TODO: Fix transparent pixels at the output image border because of Inset
|
||||
images = append(images, &imgCopy)
|
||||
// TODO: Fix transparent pixels at the output image border because of inset
|
||||
// TODO: Fix downscaled images to cause artifacts because of the inset
|
||||
}
|
||||
}
|
||||
|
||||
@ -104,15 +106,16 @@ func Stitch(tiles []imageTile, destImage *image.RGBA) error {
|
||||
|
||||
// StitchGrid calls stitch, but divides the workload into a grid of chunks.
|
||||
// Additionally it runs the workload multithreaded.
|
||||
func StitchGrid(tiles []imageTile, destImage *image.RGBA, gridSize int) (errResult error) {
|
||||
func StitchGrid(tiles []imageTile, destImage *image.RGBA, gridSize int, bar *pb.ProgressBar) (errResult error) {
|
||||
//workloads := gridifyRectangle(destImage.Bounds(), gridSize)
|
||||
workloads, err := hilbertifyRectangle(destImage.Bounds(), gridSize)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
bar := progressbar.New(len(workloads))
|
||||
bar.RenderBlank()
|
||||
if bar != nil {
|
||||
bar.SetTotal(int64(len(workloads))).Start()
|
||||
}
|
||||
|
||||
// Start worker threads
|
||||
wc := make(chan image.Rectangle)
|
||||
@ -125,7 +128,9 @@ func StitchGrid(tiles []imageTile, destImage *image.RGBA, gridSize int) (errResu
|
||||
if err := Stitch(tiles, destImage.SubImage(workload).(*image.RGBA)); err != nil {
|
||||
errResult = err // This will not stop execution, but at least one of any errors is returned.
|
||||
}
|
||||
bar.Add(1)
|
||||
if bar != nil {
|
||||
bar.Increment()
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
@ -139,9 +144,6 @@ func StitchGrid(tiles []imageTile, destImage *image.RGBA, gridSize int) (errResu
|
||||
close(wc)
|
||||
wg.Wait()
|
||||
|
||||
// Newline because of the progress bar
|
||||
fmt.Println("")
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -18,23 +18,15 @@ type MedianBlendedImage struct {
|
||||
tiles []imageTile
|
||||
bounds image.Rectangle
|
||||
|
||||
cachedRow *image.RGBA
|
||||
cachedRow *image.RGBA
|
||||
queryCounter int
|
||||
}
|
||||
|
||||
// NewMedianBlendedImage creates a new image from several single image tiles.
|
||||
func NewMedianBlendedImage(tiles []imageTile) *MedianBlendedImage {
|
||||
totalBounds := image.Rectangle{}
|
||||
for i, tile := range tiles {
|
||||
if i == 0 {
|
||||
totalBounds = tile.Bounds()
|
||||
} else {
|
||||
totalBounds = totalBounds.Union(tile.Bounds())
|
||||
}
|
||||
}
|
||||
|
||||
func NewMedianBlendedImage(tiles []imageTile, bounds image.Rectangle) *MedianBlendedImage {
|
||||
return &MedianBlendedImage{
|
||||
tiles: tiles,
|
||||
bounds: totalBounds,
|
||||
bounds: bounds,
|
||||
cachedRow: &image.RGBA{},
|
||||
}
|
||||
}
|
||||
@ -56,6 +48,9 @@ func (mbi *MedianBlendedImage) Bounds() image.Rectangle {
|
||||
func (mbi *MedianBlendedImage) At(x, y int) color.Color {
|
||||
p := image.Point{x, y}
|
||||
|
||||
// Assume that every pixel is only queried once
|
||||
mbi.queryCounter++
|
||||
|
||||
if !p.In(mbi.cachedRow.Bounds()) {
|
||||
// Need to create a new row image
|
||||
rect := mbi.Bounds()
|
||||
@ -69,10 +64,17 @@ func (mbi *MedianBlendedImage) At(x, y int) color.Color {
|
||||
mbi.cachedRow = image.NewRGBA(rect)
|
||||
|
||||
// TODO: Don't use hilbert curve here
|
||||
if err := StitchGrid(mbi.tiles, mbi.cachedRow, 512); err != nil {
|
||||
if err := StitchGrid(mbi.tiles, mbi.cachedRow, 512, nil); err != nil {
|
||||
return color.RGBA{}
|
||||
}
|
||||
}
|
||||
|
||||
return mbi.cachedRow.RGBAAt(x, y)
|
||||
}
|
||||
|
||||
// Progress returns the approximate progress of any process that scans the image from top to bottom.
|
||||
func (mbi *MedianBlendedImage) Progress() (value, max int) {
|
||||
size := mbi.Bounds().Size()
|
||||
|
||||
return mbi.queryCounter, size.X * size.Y
|
||||
}
|
||||
|
@ -13,7 +13,10 @@ import (
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/cheggaaa/pb/v3"
|
||||
"github.com/manifoldco/promptui"
|
||||
)
|
||||
|
||||
@ -24,7 +27,7 @@ var flagXMin = flag.Int("xmin", 0, "Left bound of the output rectangle. This coo
|
||||
var flagYMin = flag.Int("ymin", 0, "Upper bound of the output rectangle. This coordinate is included in the output.")
|
||||
var flagXMax = flag.Int("xmax", 0, "Right bound of the output rectangle. This coordinate is not included in the output.")
|
||||
var flagYMax = flag.Int("ymax", 0, "Lower bound of the output rectangle. This coordinate is not included in the output.")
|
||||
var flagLowRAM = flag.Bool("lowram", true, "Reduces the needed ram drastically, at the expense of speed.")
|
||||
var flagPrerender = flag.Bool("prerender", false, "Pre renders the image in RAM before saving. Can speed things up if you have enough RAM.")
|
||||
|
||||
func main() {
|
||||
flag.Parse()
|
||||
@ -155,16 +158,44 @@ func main() {
|
||||
}
|
||||
|
||||
var outputImage image.Image
|
||||
if *flagLowRAM {
|
||||
outputImage = NewMedianBlendedImage(tiles)
|
||||
} else {
|
||||
bar := pb.Full.New(0)
|
||||
var wg sync.WaitGroup
|
||||
done := make(chan bool)
|
||||
|
||||
if *flagPrerender {
|
||||
log.Printf("Creating output image with a size of %v", outputRect.Size())
|
||||
tempImage := image.NewRGBA(outputRect)
|
||||
|
||||
log.Printf("Stitching %v tiles into an image at %v", len(tiles), outputImage.Bounds())
|
||||
if err := StitchGrid(tiles, tempImage, 512); err != nil {
|
||||
log.Printf("Stitching %v tiles into an image at %v", len(tiles), tempImage.Bounds())
|
||||
if err := StitchGrid(tiles, tempImage, 512, bar); err != nil {
|
||||
log.Panic(err)
|
||||
}
|
||||
bar.Finish()
|
||||
|
||||
outputImage = tempImage
|
||||
} else {
|
||||
tempImage := NewMedianBlendedImage(tiles, outputRect)
|
||||
_, max := tempImage.Progress()
|
||||
bar.SetTotal(int64(max)).Start().SetRefreshRate(1 * time.Second)
|
||||
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
|
||||
ticker := time.NewTicker(1 * time.Second)
|
||||
for {
|
||||
select {
|
||||
case <-done:
|
||||
value, _ := tempImage.Progress()
|
||||
bar.SetCurrent(int64(value))
|
||||
bar.Finish()
|
||||
return
|
||||
case <-ticker.C:
|
||||
value, _ := tempImage.Progress()
|
||||
bar.SetCurrent(int64(value))
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
outputImage = tempImage
|
||||
}
|
||||
@ -180,6 +211,11 @@ func main() {
|
||||
log.Panic(err)
|
||||
}
|
||||
|
||||
if !*flagPrerender {
|
||||
done <- true
|
||||
wg.Wait()
|
||||
}
|
||||
|
||||
if err := f.Close(); err != nil {
|
||||
log.Panic(err)
|
||||
}
|
||||
|
3
go.mod
3
go.mod
@ -5,13 +5,14 @@ go 1.13
|
||||
require (
|
||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802 // indirect
|
||||
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d // indirect
|
||||
github.com/cheggaaa/pb/v3 v3.0.2
|
||||
github.com/gen2brain/shm v0.0.0-20180314170312-6c18ff7f8b90 // indirect
|
||||
github.com/google/hilbert v0.0.0-20181122061418-320f2e35a565
|
||||
github.com/kbinani/screenshot v0.0.0-20190719135742-f06580e30cdc
|
||||
github.com/lxn/win v0.0.0-20190919090605-24c5960b03d8 // indirect
|
||||
github.com/manifoldco/promptui v0.3.2
|
||||
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646
|
||||
github.com/schollz/progressbar/v2 v2.14.0
|
||||
github.com/schollz/progressbar/v2 v2.14.0 // indirect
|
||||
github.com/tcnksm/go-input v0.0.0-20180404061846-548a7d7a8ee8 // indirect
|
||||
golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8
|
||||
gopkg.in/alecthomas/kingpin.v3-unstable v3.0.0-20180810215634-df19058c872c // indirect
|
||||
|
14
go.sum
14
go.sum
@ -1,9 +1,14 @@
|
||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802 h1:1BDTz0u9nC3//pOCMdNH+CiXJVYJh5UQNCOBG7jbELc=
|
||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||
github.com/VividCortex/ewma v1.1.1 h1:MnEK4VOv6n0RSY4vtRe3h11qjxL3+t0B8yOL8iMXdcM=
|
||||
github.com/VividCortex/ewma v1.1.1/go.mod h1:2Tkkvm3sRDVXaiyucHiACn4cqf7DpdyLvmxzcbUokwA=
|
||||
github.com/alecthomas/gometalinter v2.0.11+incompatible h1:ENdXMllZNSVDTJUUVIzBW9CSEpntTrQa76iRsEFLX/M=
|
||||
github.com/alecthomas/gometalinter v2.0.11+incompatible/go.mod h1:qfIpQGGz3d+NmgyPBqv+LSh50emm1pt72EtcX2vKYQk=
|
||||
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d h1:UQZhZ2O0vMHr2cI+DC1Mbh0TJxzA3RcLoMsFw+aXw7E=
|
||||
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=
|
||||
github.com/cheggaaa/pb v2.0.7+incompatible h1:gLKifR1UkZ/kLkda5gC0K6c8g+jU2sINPtBeOiNlMhU=
|
||||
github.com/cheggaaa/pb/v3 v3.0.2 h1:/u+zw5RBzW1CxRpVIqrZv4PpZpN+yaRPdsRORKyDjv4=
|
||||
github.com/cheggaaa/pb/v3 v3.0.2/go.mod h1:SqqeMF/pMOIu3xgGoxtPYhMNQP258xE4x/XRTYua+KU=
|
||||
github.com/chzyer/logex v1.1.10 h1:Swpa1K6QvQznwJRcfTfQJmTE72DqScAa40E+fbHEXEE=
|
||||
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
|
||||
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
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys=
|
||||
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
||||
github.com/gen2brain/shm v0.0.0-20180314170312-6c18ff7f8b90 h1:QagTG5rauLt6pVVEhnVSrlIX4ifhVIZOwmw6x6D8TUw=
|
||||
github.com/gen2brain/shm v0.0.0-20180314170312-6c18ff7f8b90/go.mod h1:uF6rMu/1nvu+5DpiRLwusA6xB8zlkNoGzKn8lmYONUo=
|
||||
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
|
||||
github.com/manifoldco/promptui v0.3.2/go.mod h1:8JU+igZ+eeiiRku4T5BjtKh2ms8sziGpSYl1gN8Bazw=
|
||||
github.com/mattn/go-colorable v0.0.9 h1:UVL0vNpWh04HeJXV0KLcaT7r06gOH2l4OW6ddYRUIY4=
|
||||
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
|
||||
github.com/mattn/go-colorable v0.1.2 h1:/bC9yWikZXAL9uJdulbSfyVNIR3n3trXl+v8+1sx8mU=
|
||||
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
||||
github.com/mattn/go-isatty v0.0.4 h1:bnP0vzxcAdeI1zdubAl5PjU6zsERjGZb7raWodagDYs=
|
||||
github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
||||
github.com/mattn/go-isatty v0.0.8 h1:HLtExJ+uU2HOZ+wI0Tt5DtUDrx8yhUqDcp7fYERX4CE=
|
||||
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||
github.com/mattn/go-runewidth v0.0.4 h1:2BvfKmzob6Bmd4YsL0zygOqfdFnK7GR4QL06Do4/p7Y=
|
||||
github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
|
||||
github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db h1:62I3jR2EmQ4l5rM/4FEfDWcRD+abF5XlKShorW5LRoQ=
|
||||
github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db/go.mod h1:l0dey0ia/Uv7NcFFVbCLtqEBQbrT4OCwCSKTEv6enCw=
|
||||
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
|
||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3 h1:x/bBzNauLQAlE3fLku/xy92Y8QwKX5HZymrMz2IiKFc=
|
||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd h1:DBH9mDw0zluJT/R+nGuV3jWFWLFaHyYZWD4tOT+cjn0=
|
||||
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
|
Loading…
Reference in New Issue
Block a user