Start work on tile stitcher

This commit is contained in:
David Vogel 2019-10-21 02:07:39 +02:00
parent f4db31f7e1
commit dbcab2ffc6
5 changed files with 194 additions and 4 deletions

57
bin/stitch/imagetile.go Normal file
View 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
View 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
View 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
View 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())
}

View File

@ -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)