kopia lustrzana https://github.com/halfmonty/StringArtGenerator
main.go
rodzic
3ec3f9763e
commit
215be81cb5
|
@ -0,0 +1,207 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"image"
|
||||
"image/jpeg"
|
||||
"github.com/antha-lang/antha/antha/anthalib/num"
|
||||
"os"
|
||||
"io"
|
||||
"time"
|
||||
"strconv"
|
||||
"syscall/js"
|
||||
)
|
||||
|
||||
//**********************//
|
||||
// Structs //
|
||||
//**********************//
|
||||
type Coord struct {
|
||||
X float64
|
||||
Y float64
|
||||
}
|
||||
|
||||
const PINS = 300
|
||||
const MIN_DISTANCE = 30
|
||||
const MAX_LINES = 4000
|
||||
const LINE_WEIGHT = 8
|
||||
var IMG_SIZE = 500
|
||||
var IMG_SIZE_FL = float64(500)
|
||||
var IMG_SIZE_SQ = 250000
|
||||
var Pin_coords = []Coord{}
|
||||
var SourceImage = []float64{}
|
||||
var Line_cache_y = [][]float64{}
|
||||
var Line_cache_x = [][]float64{}
|
||||
|
||||
//**********************//
|
||||
// Main //
|
||||
//**********************//
|
||||
|
||||
func init(){
|
||||
image.RegisterFormat("jpeg", "jpeg", jpeg.Decode, jpeg.DecodeConfig)
|
||||
}
|
||||
|
||||
func main() {
|
||||
SourceImage = importPictureAndGetPixelArray()
|
||||
fmt.Println("Hello, world.")
|
||||
|
||||
startTime := time.Now()
|
||||
calculatePinCoords()
|
||||
precalculateAllPotentialLines()
|
||||
calculateLines()
|
||||
endTime := time.Now()
|
||||
diff := endTime.Sub(startTime)
|
||||
fmt.Println(" precalculateAllPotentialLines Taken, " + strconv.FormatFloat(diff.Seconds(), 'f', 6, 64))
|
||||
|
||||
fmt.Println("End")
|
||||
}
|
||||
|
||||
func generateStringArt()
|
||||
|
||||
func importPictureAndGetPixelArray() []float64 {
|
||||
imgfile, _ := os.Open("./ae300.jpg")
|
||||
|
||||
defer imgfile.Close()
|
||||
pixels, _ := getPixels(imgfile)
|
||||
return pixels
|
||||
}
|
||||
|
||||
func getPixels(file io.Reader) ([]float64, error) {
|
||||
img, _, err := image.Decode(file)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
bounds := img.Bounds()
|
||||
width, height := bounds.Max.X, bounds.Max.Y
|
||||
IMG_SIZE = width
|
||||
IMG_SIZE_FL = float64(IMG_SIZE)
|
||||
IMG_SIZE_SQ = IMG_SIZE * IMG_SIZE
|
||||
|
||||
var pixels []float64
|
||||
for y := 0; y < height; y++ {
|
||||
for x := 0; x < width; x++ {
|
||||
pixels = append(pixels, rgbaToPixel(img.At(x, y).RGBA()))
|
||||
}
|
||||
}
|
||||
|
||||
return pixels, nil
|
||||
}
|
||||
|
||||
func rgbaToPixel(r uint32, g uint32, b uint32, a uint32) float64 {
|
||||
return float64(r / 257)
|
||||
}
|
||||
|
||||
func calculatePinCoords() {
|
||||
pin_coords := [PINS]Coord{}
|
||||
|
||||
center := float64(IMG_SIZE / 2)
|
||||
radius := float64(IMG_SIZE/2 - 1)
|
||||
|
||||
for i:=0;i<PINS;i++ {
|
||||
angle := 2 * math.Pi * float64(i) / float64(PINS)
|
||||
pin_coords[i] = Coord{X : math.Floor(center + radius*math.Cos(angle)), Y : math.Floor(center + radius*math.Sin(angle))}
|
||||
}
|
||||
|
||||
Pin_coords = pin_coords[:]
|
||||
}
|
||||
|
||||
func precalculateAllPotentialLines() {
|
||||
line_cache_y := [PINS * PINS][]float64{}
|
||||
line_cache_x := [PINS * PINS][]float64{}
|
||||
|
||||
for i := 0; i < PINS; i++ {
|
||||
for j := i + MIN_DISTANCE; j < PINS; j++ {
|
||||
x0 := Pin_coords[i].X
|
||||
y0 := Pin_coords[i].Y
|
||||
|
||||
x1 := Pin_coords[j].X
|
||||
y1 := Pin_coords[j].Y
|
||||
|
||||
d := math.Floor(math.Sqrt(float64((x1-x0)*(x1-x0) + (y1-y0)*(y1-y0))))
|
||||
xs := roundUpFloatArrayToInt(num.Linspace(float64(x0), float64(x1), int(d)))
|
||||
ys := roundUpFloatArrayToInt(num.Linspace(float64(y0), float64(y1), int(d)))
|
||||
|
||||
line_cache_y[j*PINS+i] = ys
|
||||
line_cache_y[i*PINS+j] = ys
|
||||
line_cache_x[j*PINS+i] = xs
|
||||
line_cache_x[i*PINS+j] = xs
|
||||
}
|
||||
}
|
||||
Line_cache_y = line_cache_y[:][:]
|
||||
Line_cache_x = line_cache_x[:][:]
|
||||
}
|
||||
|
||||
func roundUpFloatArrayToInt(arr []float64) []float64 {
|
||||
for i:= range arr {
|
||||
arr[i] = float64(int(arr[i]))
|
||||
}
|
||||
return arr
|
||||
}
|
||||
|
||||
func calculateLines() {
|
||||
fmt.Println("Drawing Lines....")
|
||||
error := num.Sub(num.MulByConst(num.Ones(IMG_SIZE_SQ), float64(255)), SourceImage)
|
||||
|
||||
line_sequence := make([]int, 1, 4096)
|
||||
current_pin := 0
|
||||
last_pins := make([]int, 20, 24)
|
||||
best_pin := -1
|
||||
line_err := float64(0)
|
||||
max_err := float64(0)
|
||||
index := 0
|
||||
inner_index := 0
|
||||
for i := 0; i < MAX_LINES; i++ {
|
||||
best_pin = -1
|
||||
line_err = float64(0)
|
||||
max_err = float64(0)
|
||||
|
||||
for offset := MIN_DISTANCE; offset < PINS - MIN_DISTANCE; offset++ {
|
||||
test_pin := (current_pin + offset) % PINS
|
||||
if(contains(last_pins, test_pin)){
|
||||
continue;
|
||||
} else {
|
||||
inner_index = test_pin * PINS + current_pin
|
||||
|
||||
line_err = getLineErr(error, Line_cache_y[inner_index], Line_cache_x[inner_index])
|
||||
if( line_err > max_err){
|
||||
max_err = line_err
|
||||
best_pin = test_pin
|
||||
index = inner_index
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
line_sequence = append(line_sequence, best_pin)
|
||||
|
||||
coords1:=Line_cache_y[index]
|
||||
coords2:=Line_cache_x[index]
|
||||
for i := range coords1 {
|
||||
v := int((coords1[i] * IMG_SIZE_FL) + coords2[i])
|
||||
error[v] = error[v] - LINE_WEIGHT
|
||||
}
|
||||
|
||||
last_pins = append(last_pins, best_pin)
|
||||
last_pins = last_pins[1:]
|
||||
current_pin = best_pin
|
||||
}
|
||||
fmt.Println(line_sequence)
|
||||
}
|
||||
|
||||
func getLineErr(err, coords1, coords2 []float64) float64 {
|
||||
sum := float64(0)
|
||||
for i:=0;i<len(coords1);i++{
|
||||
sum = sum + err[int((coords1[i] * IMG_SIZE_FL) + coords2[i])]
|
||||
}
|
||||
return sum
|
||||
}
|
||||
|
||||
func contains(arr []int, num int) bool {
|
||||
for i := range arr {
|
||||
if arr[i] == num {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
Ładowanie…
Reference in New Issue