mirror of
https://github.com/Dadido3/noita-mapcap.git
synced 2024-11-18 17:17:31 +00:00
Start work on tile stitcher
This commit is contained in:
parent
f4db31f7e1
commit
dbcab2ffc6
57
bin/stitch/imagetile.go
Normal file
57
bin/stitch/imagetile.go
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
// Copyright (c) 2019 David Vogel
|
||||||
|
//
|
||||||
|
// This software is released under the MIT License.
|
||||||
|
// https://opensource.org/licenses/MIT
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"image"
|
||||||
|
_ "image/png"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
type imageTile struct {
|
||||||
|
fileName string
|
||||||
|
|
||||||
|
originalRect image.Rectangle // Rectangle of the original position. Determined by the file name, the real coordinates may differ a few pixels.
|
||||||
|
image image.Image // Either a rectangle or an RGBA image. The bounds of this image represent the real and corrected coordinates.
|
||||||
|
}
|
||||||
|
|
||||||
|
func (it *imageTile) loadImage() error {
|
||||||
|
// Check if the image is already loaded
|
||||||
|
if _, ok := it.image.(*image.RGBA); ok {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Store rectangle of the old image
|
||||||
|
oldRect := it.image.Bounds()
|
||||||
|
|
||||||
|
file, err := os.Open(it.fileName)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
|
||||||
|
img, _, err := image.Decode(file)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
imgRGBA, ok := img.(*image.RGBA)
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("Expected an RGBA image, got %T instead", img)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Restore the position of the image rectangle
|
||||||
|
imgRGBA.Rect = imgRGBA.Rect.Add(oldRect.Min)
|
||||||
|
|
||||||
|
it.image = imgRGBA
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (it *imageTile) unloadImage() {
|
||||||
|
it.image = it.image.Bounds()
|
||||||
|
}
|
54
bin/stitch/imagetiles.go
Normal file
54
bin/stitch/imagetiles.go
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
// Copyright (c) 2019 David Vogel
|
||||||
|
//
|
||||||
|
// This software is released under the MIT License.
|
||||||
|
// https://opensource.org/licenses/MIT
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"image"
|
||||||
|
"path/filepath"
|
||||||
|
"regexp"
|
||||||
|
"strconv"
|
||||||
|
)
|
||||||
|
|
||||||
|
var regexFileParse = regexp.MustCompile(`^(-?\d+),(-?\d+).png$`)
|
||||||
|
|
||||||
|
func loadImages(path string) ([]imageTile, error) {
|
||||||
|
var imageTiles []imageTile
|
||||||
|
|
||||||
|
files, err := filepath.Glob(filepath.Join(inputPath, "*.png"))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, file := range files {
|
||||||
|
baseName := filepath.Base(file)
|
||||||
|
result := regexFileParse.FindStringSubmatch(baseName)
|
||||||
|
var x, y int
|
||||||
|
if parsed, err := strconv.ParseInt(result[1], 10, 0); err == nil {
|
||||||
|
x = int(parsed)
|
||||||
|
} else {
|
||||||
|
return nil, fmt.Errorf("Error parsing %v to integer: %w", result[1], err)
|
||||||
|
}
|
||||||
|
if parsed, err := strconv.ParseInt(result[2], 10, 0); err == nil {
|
||||||
|
y = int(parsed)
|
||||||
|
} else {
|
||||||
|
return nil, fmt.Errorf("Error parsing %v to integer: %w", result[2], err)
|
||||||
|
}
|
||||||
|
|
||||||
|
width, height, err := getImageFileDimension(file)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
imageTiles = append(imageTiles, imageTile{
|
||||||
|
fileName: file,
|
||||||
|
originalRect: image.Rect(x, y, x+width, y+height),
|
||||||
|
image: image.Rect(x, y, x+width, y+height),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return imageTiles, nil
|
||||||
|
}
|
25
bin/stitch/stitch.go
Normal file
25
bin/stitch/stitch.go
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
// Copyright (c) 2019 David Vogel
|
||||||
|
//
|
||||||
|
// This software is released under the MIT License.
|
||||||
|
// https://opensource.org/licenses/MIT
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"path/filepath"
|
||||||
|
)
|
||||||
|
|
||||||
|
var inputPath = filepath.Join(".", "..", "..", "output")
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
tiles, err := loadImages(inputPath)
|
||||||
|
if err != nil {
|
||||||
|
log.Panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tile := range tiles {
|
||||||
|
fmt.Printf("%v\n", tile)
|
||||||
|
}
|
||||||
|
}
|
53
bin/stitch/util.go
Normal file
53
bin/stitch/util.go
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
// Copyright (c) 2019 David Vogel
|
||||||
|
//
|
||||||
|
// This software is released under the MIT License.
|
||||||
|
// https://opensource.org/licenses/MIT
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"image"
|
||||||
|
"math"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Source: https://gist.github.com/sergiotapia/7882944
|
||||||
|
func getImageFileDimension(imagePath string) (int, int, error) {
|
||||||
|
file, err := os.Open(imagePath)
|
||||||
|
if err != nil {
|
||||||
|
return 0, 0, fmt.Errorf("Can't open file %v: %w", imagePath, err)
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
|
||||||
|
image, _, err := image.DecodeConfig(file)
|
||||||
|
if err != nil {
|
||||||
|
return 0, 0, fmt.Errorf("Error decoding config of image file %v: %w", imagePath, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return image.Width, image.Height, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// getImageDifferenceValue returns the average quadratic difference of the (sub)pixels
|
||||||
|
func getImageDifferenceValue(a, b *image.RGBA) float64 {
|
||||||
|
intersection := a.Bounds().Intersect(b.Bounds())
|
||||||
|
|
||||||
|
if intersection.Empty() {
|
||||||
|
return math.Inf(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
aSub := a.SubImage(intersection).(*image.RGBA)
|
||||||
|
bSub := b.SubImage(intersection).(*image.RGBA)
|
||||||
|
|
||||||
|
value := 0.0
|
||||||
|
|
||||||
|
for iy := 0; iy < intersection.Dy(); iy++ {
|
||||||
|
for ix := 0; ix < intersection.Dx()*4; ix++ {
|
||||||
|
aValue := float64(aSub.Pix[ix+iy*aSub.Stride])
|
||||||
|
bValue := float64(bSub.Pix[ix+iy*bSub.Stride])
|
||||||
|
value += math.Pow(aValue-bValue, 2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return value / float64(intersection.Dx()*intersection.Dy())
|
||||||
|
}
|
@ -14,6 +14,7 @@ if not async then -- Check if lib is already loaded
|
|||||||
dofile("data/scripts/lib/coroutines.lua")
|
dofile("data/scripts/lib/coroutines.lua")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local CAPTURE_PIXEL_SIZE = 2 -- in FullHD a ingame pixel is expected to be 2 real pixels
|
||||||
local CAPTURE_GRID_SIZE = 128 -- in ingame pixels
|
local CAPTURE_GRID_SIZE = 128 -- in ingame pixels
|
||||||
local CAPTURE_DELAY = 15 -- in frames
|
local CAPTURE_DELAY = 15 -- in frames
|
||||||
local CAPTURE_FORCE_HP = 40 -- * 25HP
|
local CAPTURE_FORCE_HP = 40 -- * 25HP
|
||||||
@ -109,14 +110,14 @@ local function startCapturing()
|
|||||||
function()
|
function()
|
||||||
-- +x
|
-- +x
|
||||||
for i = 1, i, 1 do
|
for i = 1, i, 1 do
|
||||||
TriggerCapture(x, y)
|
TriggerCapture(x * CAPTURE_PIXEL_SIZE, y * CAPTURE_PIXEL_SIZE)
|
||||||
x, y = x + CAPTURE_GRID_SIZE, y
|
x, y = x + CAPTURE_GRID_SIZE, y
|
||||||
GameSetCameraPos(x, y)
|
GameSetCameraPos(x, y)
|
||||||
wait(CAPTURE_DELAY)
|
wait(CAPTURE_DELAY)
|
||||||
end
|
end
|
||||||
-- +y
|
-- +y
|
||||||
for i = 1, i, 1 do
|
for i = 1, i, 1 do
|
||||||
TriggerCapture(x, y)
|
TriggerCapture(x * CAPTURE_PIXEL_SIZE, y * CAPTURE_PIXEL_SIZE)
|
||||||
x, y = x, y + CAPTURE_GRID_SIZE
|
x, y = x, y + CAPTURE_GRID_SIZE
|
||||||
GameSetCameraPos(x, y)
|
GameSetCameraPos(x, y)
|
||||||
wait(CAPTURE_DELAY)
|
wait(CAPTURE_DELAY)
|
||||||
@ -124,14 +125,14 @@ local function startCapturing()
|
|||||||
i = i + 1
|
i = i + 1
|
||||||
-- -x
|
-- -x
|
||||||
for i = 1, i, 1 do
|
for i = 1, i, 1 do
|
||||||
TriggerCapture(x, y)
|
TriggerCapture(x * CAPTURE_PIXEL_SIZE, y * CAPTURE_PIXEL_SIZE)
|
||||||
x, y = x - CAPTURE_GRID_SIZE, y
|
x, y = x - CAPTURE_GRID_SIZE, y
|
||||||
GameSetCameraPos(x, y)
|
GameSetCameraPos(x, y)
|
||||||
wait(CAPTURE_DELAY)
|
wait(CAPTURE_DELAY)
|
||||||
end
|
end
|
||||||
-- -y
|
-- -y
|
||||||
for i = 1, i, 1 do
|
for i = 1, i, 1 do
|
||||||
TriggerCapture(x, y)
|
TriggerCapture(x * CAPTURE_PIXEL_SIZE, y * CAPTURE_PIXEL_SIZE)
|
||||||
x, y = x, y - CAPTURE_GRID_SIZE
|
x, y = x, y - CAPTURE_GRID_SIZE
|
||||||
GameSetCameraPos(x, y)
|
GameSetCameraPos(x, y)
|
||||||
wait(CAPTURE_DELAY)
|
wait(CAPTURE_DELAY)
|
||||||
|
Loading…
Reference in New Issue
Block a user