diff options
author | Leo Tenenbaum <pommicket@gmail.com> | 2019-06-10 17:45:38 -0400 |
---|---|---|
committer | Leo Tenenbaum <pommicket@gmail.com> | 2019-06-10 17:45:38 -0400 |
commit | 231f9ca2784217a1b454999cf1ebc9410207f85b (patch) | |
tree | 9e815dbdde6477a9a37fd7aa87ffb2f1fd2fc718 /autodistortion |
Initial commit
Diffstat (limited to 'autodistortion')
-rw-r--r-- | autodistortion/autodistortion.go | 121 |
1 files changed, 121 insertions, 0 deletions
diff --git a/autodistortion/autodistortion.go b/autodistortion/autodistortion.go new file mode 100644 index 0000000..0804402 --- /dev/null +++ b/autodistortion/autodistortion.go @@ -0,0 +1,121 @@ +/* +Copyright (C) 2019 Leo Tenenbaum + +This file is part of AutoDistortion. + +AutoDistortion is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +AutoDistortion is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with AutoDistortion. If not, see <https://www.gnu.org/licenses/>. +*/ +package autodistortion + +import ( + "image" + "image/color" + "github.com/pommicket/autodistortion/autoutils" +) + +func mod(a int, b int) int { + // Because a % b is the remainder, not modulus! + return ((a % b) + b) % b +} + +type workInfo struct { + img image.Image + xfunction autoutils.Function + yfunction autoutils.Function +} + +func DistortRows(info *workInfo, out [][]color.RGBA, yFrom int, yTo int, + done chan struct{}) { + + minX := info.img.Bounds().Min.X + maxX := info.img.Bounds().Max.X + minY := info.img.Bounds().Min.Y + maxY := info.img.Bounds().Max.Y + width := maxX - minX + height := maxY - minY + fwidth := float64(width) + fheight := float64(height) + + xy := make([]float64, 2) + for y := yFrom; y < yTo; y++ { + xy[1] = (float64(y) - float64(minY)) / fheight + for x := 0; x < width; x++ { + xy[0] = float64(x) / fwidth + srcX := mod(int(info.xfunction.Evaluate(xy) * fwidth), width) + minX + srcY := mod(int(info.yfunction.Evaluate(xy) * fheight), height) + minY + r, g, b, a := info.img.At(int(srcX), int(srcY)).RGBA() + out[y][x] = color.RGBA{uint8(r >> 8), uint8(g >> 8), uint8(b >> 8), + uint8(a >> 8)} + } + } + done <- struct{}{} + +} + +func Distort(img image.Image, functionLen int, nThreads int) image.Image { + rgba := image.NewRGBA(img.Bounds()) + + var xfunction autoutils.Function + var yfunction autoutils.Function + xfunction.Generate(2, functionLen) + yfunction.Generate(2, functionLen) + + minY := img.Bounds().Min.Y + maxY := img.Bounds().Max.Y + minX := img.Bounds().Min.X + maxX := img.Bounds().Max.X + width := maxX - minX + height := maxY - minY + + if width == 0 || height == 0 { + // I don't even know if this is possible, but just in case + return rgba + } + + info := workInfo{img, xfunction, yfunction} + + // Make a slice of pixels (image.RGBA.Set isn't thread safe ): ) + pixels := make([][]color.RGBA, height) + done := make(chan struct{}) + for y := 0; y < height; y++ { + pixels[y] = make([]color.RGBA, width) + } + + if nThreads > height { + nThreads = height // Don't make more than one thread per row + } + + for t := 0; t < nThreads; t++ { + yFrom := t * (height / nThreads) + minY + var yTo int + if t == nThreads - 1 { // Deal with final thread + yTo = maxY // (go to end of image) + } else { + yTo = (t+1) * (height / nThreads) + minY + } + go DistortRows(&info, pixels, yFrom, yTo, done) + } + + for y := 0; y < nThreads; y++ { + <-done // Wait for all goroutines to finish + } + + for y := 0; y < height; y++ { + for x := 0; x < width; x++ { + rgba.Set(x, y, pixels[y][x]) + } + } + + return rgba +} |