Add Voronoi blend method

This commit is contained in:
David Vogel 2022-08-13 13:58:50 +02:00
parent 615faac8e4
commit fcfd8c88ff
2 changed files with 66 additions and 0 deletions

View File

@ -39,6 +39,7 @@
"tcnksm",
"tdewolff",
"Vogel",
"Voronoi",
"xmax",
"xmin",
"ymax",

View File

@ -8,6 +8,7 @@ package main
import (
"image"
"image/color"
"math"
"sort"
)
@ -82,3 +83,67 @@ func (b BlendMethodMedian) Draw(tiles []*ImageTile, destImage *image.RGBA) {
}
}
}
// BlendMethodVoronoi maps every pixel to the tile with the closest center point distance.
// The result is basically a Voronoi partitioning.
type BlendMethodVoronoi struct {
BlendTileLimit int // If larger than 0, limits blending to the n newest tiles by file modification time.
}
// Draw implements the StitchedImageBlendMethod interface.
func (b BlendMethodVoronoi) Draw(tiles []*ImageTile, destImage *image.RGBA) {
bounds := destImage.Bounds()
if b.BlendTileLimit > 0 {
// Sort tiles by date.
sort.Slice(tiles, func(i, j int) bool { return tiles[i].modTime.After(tiles[j].modTime) })
}
// List of images corresponding to the "tiles" list.
// Can contain empty/nil entries for images that failed to load.
images := []*image.RGBA{}
for _, tile := range tiles {
images = append(images, tile.GetImage())
}
// Create arrays to be reused every pixel.
var col color.RGBA
var centerDistSqrMin int
for iy := bounds.Min.Y; iy < bounds.Max.Y; iy++ {
for ix := bounds.Min.X; ix < bounds.Max.X; ix++ {
point := image.Point{ix, iy}
count := 0
centerDistSqrMin = math.MaxInt
// Iterate through all images and create a list of colors.
for _, img := range images {
if img != nil {
if point.In(img.Bounds()) {
center := img.Bounds().Min.Add(img.Bounds().Max).Div(2)
centerDiff := point.Sub(center)
distSqr := centerDiff.X*centerDiff.X + centerDiff.Y*centerDiff.Y
if centerDistSqrMin > distSqr {
centerDistSqrMin = distSqr
col = img.RGBAAt(point.X, point.Y)
}
count++
// Limit number of tiles to blend.
// Will be ignored if the blend tile limit is 0.
if count == b.BlendTileLimit {
break
}
}
}
}
// If there were no images to get data from, ignore the pixel.
if count == 0 {
continue
}
col.A = 255
destImage.SetRGBA(ix, iy, col)
}
}
}