Skip to content

Commit

Permalink
refactoring
Browse files Browse the repository at this point in the history
  • Loading branch information
twolfe18 committed Dec 27, 2011
1 parent 008c35e commit a73d3fb
Show file tree
Hide file tree
Showing 7 changed files with 281 additions and 161 deletions.
File renamed without changes.
72 changes: 72 additions & 0 deletions Float64Point.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@

package main

import (
"os"
"image"
"image/png"
"fmt"
"rand"
"math"
)

type Float64Point struct {
X, Y float64
}

func (p Float64Point) String() string {
return fmt.Sprintf("(%.1f, %.1f)", p.X, p.Y)
}

func (p *Float64Point) Scale(s float64) {
p.X *= s
p.Y *= s
}

func (p *Float64Point) Shift(dx, dy float64) {
p.X += dx
p.Y += dy
}

func (p Float64Point) ProjectInto(bounds Float64Rectangle) {
p.X = math.Fmax(bounds.Min.X, p.X)
p.X = math.Fmin(bounds.Max.X, p.X)
p.Y = math.Fmax(bounds.Min.Y, p.Y)
p.Y = math.Fmin(bounds.Max.Y, p.Y)
}

func (v Float64Point) Rotate(theta float64) Float64Point {
// http://en.wikipedia.org/wiki/Rotation_(mathematics)#Matrix_algebra
st := math.Sin(theta)
ct := math.Cos(theta)
xp := v.X * ct - v.Y * st
yp := v.X * st + v.Y * ct
return Float64Point{xp, yp}
}

func (v Float64Point) L2Norm() float64 {
return math.Sqrt(v.X * v.X + v.Y * v.Y)
}

func PointMinus(a, b Float64Point) (r Float64Point) {
r.X = a.X - b.X
r.Y = a.Y - b.Y
return r
}

func PointPlus(a, b Float64Point) (r Float64Point) {
r.X = a.X + b.X
r.Y = a.Y + b.Y
return r
}

func DotProduct(a, b Float64Point) float64 {
return a.X * b.X + a.Y * b.Y
}

func RandomPointBetween(lo, hi Float64Point) Float64Point {
x := float64(hi.X) - rand.Float64() * float64(hi.X - lo.X)
y := float64(hi.Y) - rand.Float64() * float64(hi.Y - lo.Y)
return Float64Point{x, y}
}

33 changes: 33 additions & 0 deletions Float64Rectangle.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@

package main

import (
"os"
"image"
"image/png"
"fmt"
"rand"
"math"
)

type Float64Rectangle struct {
Min, Max Float64Point
}

func (r Float64Rectangle) Dx() (d float64) {
return r.Max.X - r.Min.X
}

func (r Float64Rectangle) Dy() (d float64) {
return r.Max.Y - r.Min.Y
}

func NewFloat64Rectangle(r image.Rectangle) (ret Float64Rectangle) {
ret.Min.X = float64(r.Min.X)
ret.Min.Y = float64(r.Min.Y)
ret.Max.X = float64(r.Max.X)
ret.Max.Y = float64(r.Max.Y)
return ret
}


132 changes: 132 additions & 0 deletions SimpleLineOpt.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@

package main

import (
"fmt"
)

const ( // TODO find a consistent way to write this with stuff in edge_detectors
LINE_EXPANSION = 1.3
PROPORTION_KEEP = 0.7
NUM_LINES = 1 //20 // 9 cells in each dim, 10 lines in each dim X 2 dims
MAX_ITER = 10
)

func later() {

// TODO have lines *mask* out the dark parts that they are covering

// TODO first try line optimization with one line

// read the image
img := nil

// initialize a whole bunch of lines randomly
bounds := NewFloat64Rectangle(img.Bounds())
lines := [NUM_LINES]Line
for i,_ := range lines {
lines[i] = RandomPointBetween(bounds.Min(), bounds.Max())
}

for iter := 0; iter < MAX_ITER; iter++ {

// optimize positions of lines

// take top 80% of the lines (by potential)
// i think this way is better than somehow specifying how long
// grid lines should be. this is less dependent on the picture (maybe)


// for remaining 20% randomly place lines on the grid
// - maybe utilize infomation about location of top 80%
// - maybe give these lines one round of optimization so they can compete

// increase each line length
for _,l := range lines {
l.ScaleLength(LINE_EXPANSION)
l.ProjectInto(bounds)
}
}

}

func main() {
base := "/Users/travis/Dropbox/code/sudoku/img/"
img := OpenImage(base + "clean_256_256.png")

// randomly place a line on the board
b := NewFloat64Point(img.Bounds())
left := RandomPointBetween(b.Min, b.Max)
right := RandomPointBetween(b.Min, b.Max)
line := Line{left, right, 1.0}

p := DefaultParams()

// see where it goes to
for iter := 0; iter < 10; iter++ {
line = LocalOptimizePotential(line, img, p)
// TODO
// copy
// draw
// write
}
}

type Params struct {
lambda_dtheta, delta_dtheta, max_dtheta float64
lambda_dx, delta_dx, max_dx float64
lambda_dy, delta_dy, max_dy float64
}

func DefaultParams() (p Params) {
p.lambda_dtheta = 1.0
p.lambda_dx = 1.0
p.lambda_dy = 1.0
p.delta_dtheta = 0.1
p.delta_dx = 0.1
p.delta_dy = 0.1
p.max_dtheta = 10.0
p.max_dx = 10.0
p.max_dy = 10.0
return p
}

func LocalOptimizePotential(line Line, img image.Image, p Params) (bestline Line) {
// TODO do some kind of branch and bound
var newline Line
bestpot := math.Inf(-1)
for dtheta := -p.max_dtheta; dtheta <= p.max_dtheta; dtheta += p.delta_dtheta {
fmt.Printf("*")
for dx := -p.max_dx; dx <= p.max_dx; dx += p.delta_dx {
for dy := -p.max_dy; dy <= p.may_dy; dy += p.delta_dy {
newline = line
newline.Rotate(dtheta)
newline.Shift(dx, dy)
p := LinePotential(newline, img)
if p > bestpot {
bestpot = p
bestline = newline
}
}
}
}
fmt.Printf("\n")
return bestline
}

func LinePotential(line Line, img image.Image) (pot float64) {
ch := make(chan WeightedPoint)
l.WeightedIterator(ch)
for wp := <-ch {
darkness := DarknessAt(img, wp.P.X, wp.P.Y)
if p.W < 0.0 || p.W > 1.0 {
panic(fmt.Sprintf("[LinePotential] weight must be in [0,1]: %.2f", p.W))
}
pot += darkness * math.Exp(-1.0 * p.W * p.W)
}
close(ch)
return pot
}



70 changes: 44 additions & 26 deletions line.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,28 +11,17 @@ import (

/******************************************************************************************/

// TODO not necessary now
/* type RadialLineVariance struct {
Dx, Dy float64 // for midpoint
Dtheta float64 // for RadialLine.rotation
Dlength float64 // duh
} */

type Line struct {
left, right Float64Point
radius float64 // std deviation of gaussian off the normal of the line
}

/******************************************************************************************/

func ShiftedMidpoint(l Line, towards Float64Point, amount float64) {
if amount <= 0.0 || amount >= 1.0 {
fmt.Printf("[ShiftLine] illegal amount: %.2f\n", amount)
os.Exit(1)
}
mp := MidPoint(l).Scale(amount)
towards.Scale(1.0 - amount)
return PointPlus(mp, towards)
func (l Line) Midpoint() (mid Float64Point) {
v := PointMinus(l.right, l.left)
v.Scale(0.5)
return PointPlus(l.left, v)
}

func (l Line) ScaleLength(scale float64) {
Expand All @@ -43,28 +32,57 @@ func (l Line) ScaleLength(scale float64) {
l.left = PointMinus(m, v)
}

func (l Line) Shift(dx, dy float64) {
l.left.Shift(dx, dy)
l.right.Shift(dx, dy)
}

func (l Line) ProjectInto(bounds Float64Rectangle) {
l.left.ProjectInto(bounds)
l.right.ProjectInto(bounds)
}

// you might think to have a function that returns a chan image.Point
// but i think this is cleaner because this way it is clear that the
// channel must be created and closed in the same place (as opposed to
// created in this function and closed by the caller)
func (l Line) Iterator(c chan image.Point) {
cur := l.left
iter := int(math.Fmax(math.Fabs(v.X), math.Fabs(v.Y)))
if iter == 0 {
c <- image.Point{int(l.left.X), int(l.right.Y)}
return
}
dx := v.X / float64(iter); dy := v.Y / float64(iter)
for i := 0; i<iter; i++ {
c <- image.Point{int(cur.X), int(cur.Y)}
}
}

// this allows for stuff like anti-aliased drawing
type WeightedPoint struct {
P image.Point
W float64
}

func (l Line) WeightedIterator(c chan WeightedPoint) {
// TODO
panic("[WeightedIterator] not implemented yet!")
}


/******************************************************************************************/

func (l Line) String() string {
return fmt.Sprintf("[%s -> %s]", l.left.String(), l.right.String())
}

func (l Line) Draw(img draw.Image) {
hl_color := image.RGBAColor{255, 0, 0, 255}
v := PointMinus(l.right, l.left)
cur := l.left
iter := int(math.Fmax(math.Fabs(v.X), math.Fabs(v.Y)))
if iter == 0 { img.Set(int(l.left.X), int(l.right.Y), hl_color) }
dx := v.X / float64(iter); dy := v.Y / float64(iter)
for i := 0; i<iter; i++ {
img.Set(int(cur.X), int(cur.Y), hl_color)
cur.X += dx; cur.Y += dy
}

func (l Line) Draw(img draw.Image, c image.Color) {
ch := make(chan image.Point)
l.LineIter(ch)
for p := <-ch { img.Set(p.X, p.Y, c) }
close(ch)
}

func (l Line) Angle(o Line) float64 {
Expand Down
49 changes: 0 additions & 49 deletions shortlines.go

This file was deleted.

Loading

0 comments on commit a73d3fb

Please sign in to comment.