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")
|
||||
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_DELAY = 15 -- in frames
|
||||
local CAPTURE_FORCE_HP = 40 -- * 25HP
|
||||
@ -109,14 +110,14 @@ local function startCapturing()
|
||||
function()
|
||||
-- +x
|
||||
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
|
||||
GameSetCameraPos(x, y)
|
||||
wait(CAPTURE_DELAY)
|
||||
end
|
||||
-- +y
|
||||
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
|
||||
GameSetCameraPos(x, y)
|
||||
wait(CAPTURE_DELAY)
|
||||
@ -124,14 +125,14 @@ local function startCapturing()
|
||||
i = i + 1
|
||||
-- -x
|
||||
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
|
||||
GameSetCameraPos(x, y)
|
||||
wait(CAPTURE_DELAY)
|
||||
end
|
||||
-- -y
|
||||
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
|
||||
GameSetCameraPos(x, y)
|
||||
wait(CAPTURE_DELAY)
|
||||
|
Loading…
Reference in New Issue
Block a user