Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

refactoring

  • Loading branch information...
commit a73d3fbf4290d2f7a7ce087c0b35ae675ac05b51 1 parent 008c35e
Travis Wolfe authored
0  edge_detctors.go → EdgeDetector.go
File renamed without changes
72 Float64Point.go
... ... @@ -0,0 +1,72 @@
  1 +
  2 +package main
  3 +
  4 +import (
  5 + "os"
  6 + "image"
  7 + "image/png"
  8 + "fmt"
  9 + "rand"
  10 + "math"
  11 +)
  12 +
  13 +type Float64Point struct {
  14 + X, Y float64
  15 +}
  16 +
  17 +func (p Float64Point) String() string {
  18 + return fmt.Sprintf("(%.1f, %.1f)", p.X, p.Y)
  19 +}
  20 +
  21 +func (p *Float64Point) Scale(s float64) {
  22 + p.X *= s
  23 + p.Y *= s
  24 +}
  25 +
  26 +func (p *Float64Point) Shift(dx, dy float64) {
  27 + p.X += dx
  28 + p.Y += dy
  29 +}
  30 +
  31 +func (p Float64Point) ProjectInto(bounds Float64Rectangle) {
  32 + p.X = math.Fmax(bounds.Min.X, p.X)
  33 + p.X = math.Fmin(bounds.Max.X, p.X)
  34 + p.Y = math.Fmax(bounds.Min.Y, p.Y)
  35 + p.Y = math.Fmin(bounds.Max.Y, p.Y)
  36 +}
  37 +
  38 +func (v Float64Point) Rotate(theta float64) Float64Point {
  39 + // http://en.wikipedia.org/wiki/Rotation_(mathematics)#Matrix_algebra
  40 + st := math.Sin(theta)
  41 + ct := math.Cos(theta)
  42 + xp := v.X * ct - v.Y * st
  43 + yp := v.X * st + v.Y * ct
  44 + return Float64Point{xp, yp}
  45 +}
  46 +
  47 +func (v Float64Point) L2Norm() float64 {
  48 + return math.Sqrt(v.X * v.X + v.Y * v.Y)
  49 +}
  50 +
  51 +func PointMinus(a, b Float64Point) (r Float64Point) {
  52 + r.X = a.X - b.X
  53 + r.Y = a.Y - b.Y
  54 + return r
  55 +}
  56 +
  57 +func PointPlus(a, b Float64Point) (r Float64Point) {
  58 + r.X = a.X + b.X
  59 + r.Y = a.Y + b.Y
  60 + return r
  61 +}
  62 +
  63 +func DotProduct(a, b Float64Point) float64 {
  64 + return a.X * b.X + a.Y * b.Y
  65 +}
  66 +
  67 +func RandomPointBetween(lo, hi Float64Point) Float64Point {
  68 + x := float64(hi.X) - rand.Float64() * float64(hi.X - lo.X)
  69 + y := float64(hi.Y) - rand.Float64() * float64(hi.Y - lo.Y)
  70 + return Float64Point{x, y}
  71 +}
  72 +
33 Float64Rectangle.go
... ... @@ -0,0 +1,33 @@
  1 +
  2 +package main
  3 +
  4 +import (
  5 + "os"
  6 + "image"
  7 + "image/png"
  8 + "fmt"
  9 + "rand"
  10 + "math"
  11 +)
  12 +
  13 +type Float64Rectangle struct {
  14 + Min, Max Float64Point
  15 +}
  16 +
  17 +func (r Float64Rectangle) Dx() (d float64) {
  18 + return r.Max.X - r.Min.X
  19 +}
  20 +
  21 +func (r Float64Rectangle) Dy() (d float64) {
  22 + return r.Max.Y - r.Min.Y
  23 +}
  24 +
  25 +func NewFloat64Rectangle(r image.Rectangle) (ret Float64Rectangle) {
  26 + ret.Min.X = float64(r.Min.X)
  27 + ret.Min.Y = float64(r.Min.Y)
  28 + ret.Max.X = float64(r.Max.X)
  29 + ret.Max.Y = float64(r.Max.Y)
  30 + return ret
  31 +}
  32 +
  33 +
132 SimpleLineOpt.go
... ... @@ -0,0 +1,132 @@
  1 +
  2 +package main
  3 +
  4 +import (
  5 + "fmt"
  6 +)
  7 +
  8 +const ( // TODO find a consistent way to write this with stuff in edge_detectors
  9 + LINE_EXPANSION = 1.3
  10 + PROPORTION_KEEP = 0.7
  11 + NUM_LINES = 1 //20 // 9 cells in each dim, 10 lines in each dim X 2 dims
  12 + MAX_ITER = 10
  13 +)
  14 +
  15 +func later() {
  16 +
  17 + // TODO have lines *mask* out the dark parts that they are covering
  18 +
  19 + // TODO first try line optimization with one line
  20 +
  21 + // read the image
  22 + img := nil
  23 +
  24 + // initialize a whole bunch of lines randomly
  25 + bounds := NewFloat64Rectangle(img.Bounds())
  26 + lines := [NUM_LINES]Line
  27 + for i,_ := range lines {
  28 + lines[i] = RandomPointBetween(bounds.Min(), bounds.Max())
  29 + }
  30 +
  31 + for iter := 0; iter < MAX_ITER; iter++ {
  32 +
  33 + // optimize positions of lines
  34 +
  35 + // take top 80% of the lines (by potential)
  36 + // i think this way is better than somehow specifying how long
  37 + // grid lines should be. this is less dependent on the picture (maybe)
  38 +
  39 +
  40 + // for remaining 20% randomly place lines on the grid
  41 + // - maybe utilize infomation about location of top 80%
  42 + // - maybe give these lines one round of optimization so they can compete
  43 +
  44 + // increase each line length
  45 + for _,l := range lines {
  46 + l.ScaleLength(LINE_EXPANSION)
  47 + l.ProjectInto(bounds)
  48 + }
  49 + }
  50 +
  51 +}
  52 +
  53 +func main() {
  54 + base := "/Users/travis/Dropbox/code/sudoku/img/"
  55 + img := OpenImage(base + "clean_256_256.png")
  56 +
  57 + // randomly place a line on the board
  58 + b := NewFloat64Point(img.Bounds())
  59 + left := RandomPointBetween(b.Min, b.Max)
  60 + right := RandomPointBetween(b.Min, b.Max)
  61 + line := Line{left, right, 1.0}
  62 +
  63 + p := DefaultParams()
  64 +
  65 + // see where it goes to
  66 + for iter := 0; iter < 10; iter++ {
  67 + line = LocalOptimizePotential(line, img, p)
  68 + // TODO
  69 + // copy
  70 + // draw
  71 + // write
  72 + }
  73 +}
  74 +
  75 +type Params struct {
  76 + lambda_dtheta, delta_dtheta, max_dtheta float64
  77 + lambda_dx, delta_dx, max_dx float64
  78 + lambda_dy, delta_dy, max_dy float64
  79 +}
  80 +
  81 +func DefaultParams() (p Params) {
  82 + p.lambda_dtheta = 1.0
  83 + p.lambda_dx = 1.0
  84 + p.lambda_dy = 1.0
  85 + p.delta_dtheta = 0.1
  86 + p.delta_dx = 0.1
  87 + p.delta_dy = 0.1
  88 + p.max_dtheta = 10.0
  89 + p.max_dx = 10.0
  90 + p.max_dy = 10.0
  91 + return p
  92 +}
  93 +
  94 +func LocalOptimizePotential(line Line, img image.Image, p Params) (bestline Line) {
  95 + // TODO do some kind of branch and bound
  96 + var newline Line
  97 + bestpot := math.Inf(-1)
  98 + for dtheta := -p.max_dtheta; dtheta <= p.max_dtheta; dtheta += p.delta_dtheta {
  99 + fmt.Printf("*")
  100 + for dx := -p.max_dx; dx <= p.max_dx; dx += p.delta_dx {
  101 + for dy := -p.max_dy; dy <= p.may_dy; dy += p.delta_dy {
  102 + newline = line
  103 + newline.Rotate(dtheta)
  104 + newline.Shift(dx, dy)
  105 + p := LinePotential(newline, img)
  106 + if p > bestpot {
  107 + bestpot = p
  108 + bestline = newline
  109 + }
  110 + }
  111 + }
  112 + }
  113 + fmt.Printf("\n")
  114 + return bestline
  115 +}
  116 +
  117 +func LinePotential(line Line, img image.Image) (pot float64) {
  118 + ch := make(chan WeightedPoint)
  119 + l.WeightedIterator(ch)
  120 + for wp := <-ch {
  121 + darkness := DarknessAt(img, wp.P.X, wp.P.Y)
  122 + if p.W < 0.0 || p.W > 1.0 {
  123 + panic(fmt.Sprintf("[LinePotential] weight must be in [0,1]: %.2f", p.W))
  124 + }
  125 + pot += darkness * math.Exp(-1.0 * p.W * p.W)
  126 + }
  127 + close(ch)
  128 + return pot
  129 +}
  130 +
  131 +
  132 +
70 line.go
@@ -11,13 +11,6 @@ import (
11 11
12 12 /******************************************************************************************/
13 13
14   -// TODO not necessary now
15   -/* type RadialLineVariance struct {
16   - Dx, Dy float64 // for midpoint
17   - Dtheta float64 // for RadialLine.rotation
18   - Dlength float64 // duh
19   -} */
20   -
21 14 type Line struct {
22 15 left, right Float64Point
23 16 radius float64 // std deviation of gaussian off the normal of the line
@@ -25,14 +18,10 @@ type Line struct {
25 18
26 19 /******************************************************************************************/
27 20
28   -func ShiftedMidpoint(l Line, towards Float64Point, amount float64) {
29   - if amount <= 0.0 || amount >= 1.0 {
30   - fmt.Printf("[ShiftLine] illegal amount: %.2f\n", amount)
31   - os.Exit(1)
32   - }
33   - mp := MidPoint(l).Scale(amount)
34   - towards.Scale(1.0 - amount)
35   - return PointPlus(mp, towards)
  21 +func (l Line) Midpoint() (mid Float64Point) {
  22 + v := PointMinus(l.right, l.left)
  23 + v.Scale(0.5)
  24 + return PointPlus(l.left, v)
36 25 }
37 26
38 27 func (l Line) ScaleLength(scale float64) {
@@ -43,28 +32,57 @@ func (l Line) ScaleLength(scale float64) {
43 32 l.left = PointMinus(m, v)
44 33 }
45 34
  35 +func (l Line) Shift(dx, dy float64) {
  36 + l.left.Shift(dx, dy)
  37 + l.right.Shift(dx, dy)
  38 +}
  39 +
46 40 func (l Line) ProjectInto(bounds Float64Rectangle) {
47 41 l.left.ProjectInto(bounds)
48 42 l.right.ProjectInto(bounds)
49 43 }
50 44
  45 +// you might think to have a function that returns a chan image.Point
  46 +// but i think this is cleaner because this way it is clear that the
  47 +// channel must be created and closed in the same place (as opposed to
  48 +// created in this function and closed by the caller)
  49 +func (l Line) Iterator(c chan image.Point) {
  50 + cur := l.left
  51 + iter := int(math.Fmax(math.Fabs(v.X), math.Fabs(v.Y)))
  52 + if iter == 0 {
  53 + c <- image.Point{int(l.left.X), int(l.right.Y)}
  54 + return
  55 + }
  56 + dx := v.X / float64(iter); dy := v.Y / float64(iter)
  57 + for i := 0; i<iter; i++ {
  58 + c <- image.Point{int(cur.X), int(cur.Y)}
  59 + }
  60 +}
  61 +
  62 +// this allows for stuff like anti-aliased drawing
  63 +type WeightedPoint struct {
  64 + P image.Point
  65 + W float64
  66 +}
  67 +
  68 +func (l Line) WeightedIterator(c chan WeightedPoint) {
  69 + // TODO
  70 + panic("[WeightedIterator] not implemented yet!")
  71 +}
  72 +
  73 +
51 74 /******************************************************************************************/
52 75
53 76 func (l Line) String() string {
54 77 return fmt.Sprintf("[%s -> %s]", l.left.String(), l.right.String())
55 78 }
56 79
57   -func (l Line) Draw(img draw.Image) {
58   - hl_color := image.RGBAColor{255, 0, 0, 255}
59   - v := PointMinus(l.right, l.left)
60   - cur := l.left
61   - iter := int(math.Fmax(math.Fabs(v.X), math.Fabs(v.Y)))
62   - if iter == 0 { img.Set(int(l.left.X), int(l.right.Y), hl_color) }
63   - dx := v.X / float64(iter); dy := v.Y / float64(iter)
64   - for i := 0; i<iter; i++ {
65   - img.Set(int(cur.X), int(cur.Y), hl_color)
66   - cur.X += dx; cur.Y += dy
67   - }
  80 +
  81 +func (l Line) Draw(img draw.Image, c image.Color) {
  82 + ch := make(chan image.Point)
  83 + l.LineIter(ch)
  84 + for p := <-ch { img.Set(p.X, p.Y, c) }
  85 + close(ch)
68 86 }
69 87
70 88 func (l Line) Angle(o Line) float64 {
49 shortlines.go
... ... @@ -1,49 +0,0 @@
1   -
2   -package main
3   -
4   -import (
5   - "fmt"
6   -)
7   -
8   -const ( // TODO find a unified way to write this with stuff in edge_detectors
9   - LINE_EXPANSION = 1.3
10   - PROPORTION_KEEP = 0.7
11   - NUM_LINES = 20 // 9 cells in each dim, 10 lines in each dim X 2 dims
12   - MAX_ITER = 10
13   -)
14   -
15   -func main() {
16   -
17   - // read the image
18   - img := nil
19   -
20   - // initialize a whole bunch of lines randomly
21   - bounds := NewFloat64Rectangle(img.Bounds())
22   - lines := [NUM_LINES]Line
23   - for i,_ := range lines {
24   - lines[i] = RandomPointBetween(bounds.Min(), bounds.Max())
25   - }
26   -
27   - for iter := 0; iter < MAX_ITER; iter++ {
28   -
29   - // optimize positions of lines
30   -
31   - // take top 80% of the lines (by potential)
32   -
33   - // for remaining 20% randomly place lines on the grid
34   - // - maybe utilize infomation about location of top 80%
35   - // - maybe give these lines one round of optimization so they can compete
36   -
37   - // increase each line length
38   - for _,l := range lines {
39   - l.ScaleLength(LINE_EXPANSION)
40   - l.ProjectInto(bounds)
41   - }
42   -
43   -}
44   -
45   -func OptimizePotential(lines []Lines, img image.Image) {
46   - // TODO maybe pass in a potential function
47   - // TODO this should be merged with Proposal() and Potenital() code in edge_detectors
48   -}
49   -
86 util.go
@@ -10,91 +10,11 @@ import (
10 10 "math"
11 11 )
12 12
13   -// TODO refactor all intstances of Float64Point in the file to two Float64Points
14   -
15   -type Float64Point struct {
16   - X, Y float64
17   -}
18   -
19   -func (p Float64Point) String() string {
20   - return fmt.Sprintf("(%.1f, %.1f)", p.X, p.Y)
21   -}
22   -
23   -func (p *Float64Point) Scale(s float64) {
24   - p.X *= s
25   - p.Y *= s
26   -}
27   -
28   -func (p Float64Point) ProjectInto(bounds Float64Rectangle) {
29   - p.X = math.Fmax(bounds.Min.X, p.X)
30   - p.X = math.Fmin(bounds.Max.X, p.X)
31   - p.Y = math.Fmax(bounds.Min.Y, p.Y)
32   - p.Y = math.Fmin(bounds.Max.Y, p.Y)
33   -}
34   -
35   -func (v Float64Point) Rotate(theta float64) Float64Point {
36   - // http://en.wikipedia.org/wiki/Rotation_(mathematics)#Matrix_algebra
37   - st := math.Sin(theta)
38   - ct := math.Cos(theta)
39   - xp := v.X * ct - v.Y * st
40   - yp := v.X * st + v.Y * ct
41   - return Float64Point{xp, yp}
42   -}
43   -
44   -func (v Float64Point) L2Norm() float64 {
45   - return math.Sqrt(v.X * v.X + v.Y * v.Y)
46   -}
47   -
48   -func PointMinus(a, b Float64Point) (r Float64Point) {
49   - r.X = a.X - b.X
50   - r.Y = a.Y - b.Y
51   - return r
52   -}
53   -
54   -func PointPlus(a, b Float64Point) (r Float64Point) {
55   - r.X = a.X + b.X
56   - r.Y = a.Y + b.Y
57   - return r
58   -}
59   -
60   -func DotProduct(a, b Float64Point) float64 {
61   - return a.X * b.X + a.Y * b.Y
62   -}
63   -
64   -type Float64Rectangle struct {
65   - Min, Max Float64Point
66   -}
67   -
68   -func (r Float64Rectangle) Dx() (d float64) {
69   - return r.Max.X - r.Min.X
70   -}
71   -
72   -func (r Float64Rectangle) Dy() (d float64) {
73   - return r.Max.Y - r.Min.Y
74   -}
75   -
76   -func NewFloat64Rectangle(r image.Rectangle) (ret Float64Rectangle) {
77   - ret.Min.X = float64(r.Min.X)
78   - ret.Min.Y = float64(r.Min.Y)
79   - ret.Max.X = float64(r.Max.X)
80   - ret.Max.Y = float64(r.Max.Y)
81   - return ret
82   -}
83   -
84 13 func max(a, b int) int {
85 14 if a > b { return a }
86 15 return b
87 16 }
88 17
89   -func Midpoint(a, b Float64Point) (mid Float64Point) {
90   - mid = a
91   - mid.X += b.X
92   - mid.X /= 2.0
93   - mid.Y += b.Y
94   - mid.Y /= 2.0
95   - return mid
96   -}
97   -
98 18 func WeightedChoice(weights []float64) int {
99 19 s := 0.0
100 20 for _,v := range weights {
@@ -118,12 +38,6 @@ func WeightedChoice(weights []float64) int {
118 38 return -1
119 39 }
120 40
121   -func RandomPointBetween(lo, hi Float64Point) Float64Point {
122   - x := float64(hi.X) - rand.Float64() * float64(hi.X - lo.X)
123   - y := float64(hi.Y) - rand.Float64() * float64(hi.Y - lo.Y)
124   - return Float64Point{x, y}
125   -}
126   -
127 41 func DarknessAt(img image.Image, x, y int) float64 {
128 42 r, g, b, _ := img.At(x, y).RGBA()
129 43 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.