Created
July 22, 2018 00:34
-
-
Save pwfff/ab5c4e26c2d92a4d1b36a22e5f1ce4ee to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"bufio" | |
"github.com/nfnt/resize" | |
"image" | |
"image/color" | |
"image/draw" | |
"image/jpeg" | |
_ "image/png" | |
"log" | |
"math/rand" | |
"os" | |
"sort" | |
"sync" | |
"time" | |
) | |
type sortRow struct { | |
start int | |
end int | |
} | |
type YSorter []color.Color | |
func (r YSorter) Len() int { return len(r) } | |
func (r YSorter) Swap(i, j int) { r[i], r[j] = r[j], r[i] } | |
func (r YSorter) Less(i, j int) bool { | |
r1, g1, b1, _ := r[i].RGBA() | |
r2, g2, b2, _ := r[j].RGBA() | |
y1, _, _ := color.RGBToYCbCr(uint8(r1>>8), uint8(g1>>8), uint8(b1>>8)) | |
y2, _, _ := color.RGBToYCbCr(uint8(r2>>8), uint8(g2>>8), uint8(b2>>8)) | |
return y1 < y2 | |
} | |
func getDrawableImage(src image.Image) draw.Image { | |
b := src.Bounds() | |
rgba := image.NewRGBA(b) | |
draw.Draw(rgba, b, src, b.Min, draw.Src) | |
return rgba | |
} | |
func getImage(path string) (draw.Image, error) { | |
file, err := os.Open(path) | |
if err != nil { | |
return nil, err | |
} | |
defer file.Close() | |
img, _, err := image.Decode(file) | |
if err != nil { | |
return nil, err | |
} | |
return getDrawableImage(img), nil | |
} | |
func fitImage(src, dest draw.Image) draw.Image { | |
bounds := src.Bounds() | |
srcWidth, srcHeight := uint(bounds.Max.X), uint(bounds.Max.Y) | |
srcRatio := float64(srcWidth) / float64(srcHeight) | |
bounds = dest.Bounds() | |
destWidth, destHeight := uint(bounds.Max.X), uint(bounds.Max.Y) | |
var fit image.Image | |
if srcRatio > 1.0 { | |
fit = resize.Resize(destWidth, 0, src, resize.Lanczos3) | |
} else { | |
fit = resize.Resize(0, destHeight, src, resize.Lanczos3) | |
} | |
return getDrawableImage(fit) | |
} | |
func getPixels(img draw.Image) [][]color.Color { | |
bounds := img.Bounds() | |
width, height := bounds.Max.X, bounds.Max.Y | |
var pixels [][]color.Color | |
for y := 0; y < height; y++ { | |
var row []color.Color | |
for x := 0; x < width; x++ { | |
row = append(row, img.At(x, y)) | |
} | |
pixels = append(pixels, row) | |
} | |
return pixels | |
} | |
func main() { | |
rand.Seed(time.Now().UTC().UnixNano()) | |
baseImage, err := getImage("city.jpg") | |
if err != nil { | |
log.Fatal(err) | |
} | |
basePixels := getPixels(baseImage) | |
maskImage, err := getImage("mask.png") | |
if err != nil { | |
log.Fatal(err) | |
} | |
maskImage = fitImage(maskImage, baseImage) | |
maskPixels := getPixels(maskImage) | |
var maskRows [][]sortRow | |
for y := range maskPixels { | |
var rows []sortRow | |
var start int | |
var inRow bool | |
row := maskPixels[y] | |
for x := range row { | |
pixel := row[x] | |
_, _, _, a := pixel.RGBA() | |
if a == 0 { | |
if inRow { | |
rows = append(rows, sortRow{start, x}) | |
inRow = false | |
} | |
} else { | |
if !inRow { | |
start = x | |
inRow = true | |
} else { | |
if rand.Float64() > .95 { | |
rows = append(rows, sortRow{start, x}) | |
inRow = false | |
} | |
} | |
} | |
} | |
maskRows = append(maskRows, rows) | |
} | |
var wg sync.WaitGroup | |
for y := range maskRows { | |
wg.Add(1) | |
go func(y int) { | |
defer wg.Done() | |
for i := range maskRows[y] { | |
row := maskRows[y][i] | |
var colors []color.Color | |
for x := row.start; x < row.end; x++ { | |
colors = append(colors, baseImage.At(x, y)) | |
} | |
sort.Sort(YSorter(colors)) | |
j := 0 | |
for x := row.start; x < row.end; x++ { | |
baseImage.Set(x, y, colors[j]) | |
j++ | |
} | |
} | |
log.Print(y) | |
}(y) | |
} | |
wg.Wait() | |
f, err := os.Create("out.jpg") | |
if err != nil { | |
log.Fatal(err) | |
} | |
defer f.Close() | |
w := bufio.NewWriter(f) | |
jpeg.Encode(w, baseImage, nil) | |
log.Print(basePixels[1][1].RGBA()) | |
log.Print(maskRows[0]) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment