Skip to content
Browse files

refactoring

  • Loading branch information...
1 parent 008c35e commit a73d3fbf4290d2f7a7ce087c0b35ae675ac05b51 @twolfe18 committed Dec 27, 2011
Showing with 281 additions and 161 deletions.
  1. 0 edge_detctors.go → EdgeDetector.go
  2. +72 −0 Float64Point.go
  3. +33 −0 Float64Rectangle.go
  4. +132 −0 SimpleLineOpt.go
  5. +44 −26 line.go
  6. +0 −49 shortlines.go
  7. +0 −86 util.go
View
0 edge_detctors.go → EdgeDetector.go
File renamed without changes.
View
72 Float64Point.go
@@ -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}
+}
+
View
33 Float64Rectangle.go
@@ -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
+}
+
+
View
132 SimpleLineOpt.go
@@ -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
+}
+
+
+
View
70 line.go
@@ -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) {
@@ -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 {
View
49 shortlines.go
@@ -1,49 +0,0 @@
-
-package main
-
-import (
- "fmt"
-)
-
-const ( // TODO find a unified way to write this with stuff in edge_detectors
- LINE_EXPANSION = 1.3
- PROPORTION_KEEP = 0.7
- NUM_LINES = 20 // 9 cells in each dim, 10 lines in each dim X 2 dims
- MAX_ITER = 10
-)
-
-func main() {
-
- // 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)
-
- // 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 OptimizePotential(lines []Lines, img image.Image) {
- // TODO maybe pass in a potential function
- // TODO this should be merged with Proposal() and Potenital() code in edge_detectors
-}
-
View
86 util.go
@@ -10,91 +10,11 @@ import (
"math"
)
-// TODO refactor all intstances of Float64Point in the file to two Float64Points
-
-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) 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
-}
-
-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
-}
-
func max(a, b int) int {
if a > b { return a }
return b
}
-func Midpoint(a, b Float64Point) (mid Float64Point) {
- mid = a
- mid.X += b.X
- mid.X /= 2.0
- mid.Y += b.Y
- mid.Y /= 2.0
- return mid
-}
-
func WeightedChoice(weights []float64) int {
s := 0.0
for _,v := range weights {
@@ -118,12 +38,6 @@ func WeightedChoice(weights []float64) int {
return -1
}
-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}
-}
-
func DarknessAt(img image.Image, x, y int) float64 {
r, g, b, _ := img.At(x, y).RGBA()
lum := 0.21 * float64(r) + 0.71 * float64(g) + 0.07 * float64(b)

0 comments on commit a73d3fb

Please sign in to comment.
Something went wrong with that request. Please try again.