-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
7 changed files
with
281 additions
and
161 deletions.
There are no files selected for viewing
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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} | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
} | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
} | ||
|
||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
Oops, something went wrong.