Skip to content

Instantly share code, notes, and snippets.

Keybase proof

I hereby claim:

  • I am sausheong on github.
  • I am sausheong (https://keybase.io/sausheong) on keybase.
  • I have a public key whose fingerprint is E86E 9A36 EF67 3777 3F86 88D3 3592 C89F 5903 A846

To claim this, I am signing this object:

@sausheong
sausheong / .go
Created December 28, 2019 12:36
photo mosaic blog 1
// find the average color of the picture
func averageColor(img image.Image) [3]float64 {
bounds := img.Bounds()
r, g, b := 0.0, 0.0, 0.0
for y := bounds.Min.Y; y < bounds.Max.Y; y++ {
for x := bounds.Min.X; x < bounds.Max.X; x++ {
r1, g1, b1, _ := img.At(x, y).RGBA()
r, g, b = r+float64(r1), g+float64(g1), b+float64(b1)
}
}
@sausheong
sausheong / .go
Created December 28, 2019 12:37
photo mosaic blog 2
// resize an image to its new width
func resize(in image.Image, newWidth int) image.NRGBA {
bounds := in.Bounds()
width := bounds.Max.X - bounds.Min.X
ratio := width / newWidth
out := image.NewNRGBA(image.Rect(bounds.Min.X/ratio, bounds.Min.X/ratio, bounds.Max.X/ratio, bounds.Max.Y/ratio))
for y, j := bounds.Min.Y, bounds.Min.Y; y < bounds.Max.Y; y, j = y+ratio, j+1 {
for x, i := bounds.Min.X, bounds.Min.X; x < bounds.Max.X; x, i = x+ratio, i+1 {
r, g, b, a := in.At(x, y).RGBA()
out.SetNRGBA(i, j, color.NRGBA{uint8(r), uint8(g), uint8(b), uint8(a)})
@sausheong
sausheong / .go
Created December 28, 2019 12:38
photo mosaic blog 3
// populate a tiles database in memory
func tilesDB() map[string][3]float64 {
fmt.Println("Start populating tiles db ...")
db := make(map[string][3]float64)
files, _ := ioutil.ReadDir("tiles")
for _, f := range files {
name := "tiles/" + f.Name()
file, err := os.Open(name)
if err == nil {
img, _, err := image.Decode(file)
@sausheong
sausheong / .go
Created December 28, 2019 12:39
photo mosaic blog 4
// find the nearest matching image
func nearest(target [3]float64, db *map[string][3]float64) string {
var filename string
smallest := 1000000.0
for k, v := range *db {
dist := distance(target, v)
if dist < smallest {
filename, smallest = k, dist
}
}
@sausheong
sausheong / .go
Created December 28, 2019 12:40
photo mosaic blog 5
// find the Eucleadian distance between 2 points
func distance(p1 [3]float64, p2 [3]float64) float64 {
return math.Sqrt(sq(p2[0]-p1[0]) + sq(p2[1]-p1[1]) + sq(p2[2]-p1[2]))
}
// find the square
func sq(n float64) float64 {
return n * n
}
@sausheong
sausheong / .go
Created December 28, 2019 12:42
photo mosaic blog 6
var TILESDB map[string][3]float64
// clone the tile database each time we generate the photo mosaic
func cloneTilesDB() map[string][3]float64 {
db := make(map[string][3]float64)
for k, v := range TILESDB {
db[k] = v
}
return db
}
@sausheong
sausheong / main.go
Created December 28, 2019 12:51
photo mosaic blog 7
package main
import (
"fmt"
"html/template"
"net/http"
"bytes"
"encoding/base64"
"image"
"image/draw"
@sausheong
sausheong / .go
Created December 28, 2019 12:55
photo mosaic blog 8
// get the content from the POSTed form
r.ParseMultipartForm(10485760) // max body in memory is 10MB
file, _, _ := r.FormFile("image")
defer file.Close()
tileSize, _ := strconv.Atoi(r.FormValue("tile_size"))
@sausheong
sausheong / .go
Created December 28, 2019 12:56
photo mosaic blog 9
// decode and get original image
original, _, _ := image.Decode(file)
bounds := original.Bounds()
// create a new image for the mosaic
newimage := image.NewNRGBA(image.Rect(bounds.Min.X, bounds.Min.X, bounds.Max.X, bounds.Max.Y))