fogleman / primitive

Reproducing images with geometric primitives.
https://primitive.lol/
MIT License
12.35k stars 608 forks source link

Going through all mode instead of random #21

Closed bmaltais closed 7 years ago

bmaltais commented 7 years ago

OK, so I pushed my original idea of going through all different mode at each iteration to pich the best form providing the lowest score. The result is that the final score doing it that way is significantly lower than just using mode 1. Mode 1 usually provide the best score of all methods.

http://imgur.com/a/11jDL

As you can see even with a lower score the triangle method provide the best looking image to my eye... but it is interesting to see that you can get lower score bay going through all possible shapes. Here is the code I used. Not optimal but you might want to try it:

func (model *Model) BestHillClimbState(buffer *image.RGBA, t ShapeType, a, n, age, m int, rnd *rand.Rand) *State {
    var bestEnergy float64
    var bestState *State
    //v("%d\n",m)
    if t != 0 {
        for i := 0; i < m; i++ {
            state := model.BestRandomState(buffer, t, a, n, rnd)
            before := state.Energy()
            state = HillClimb(state, age).(*State)
            energy := state.Energy()
            vv("%dx random: %.6f -> %dx hill climb: %.6f\n", n, before, age, energy)
            if i == 0 || energy < bestEnergy {
                bestEnergy = energy
                bestState = state
            }
        }
    } else {
        for j := 1; j < 6; j++ {
            for i := 0; i < m; i++ {
                state := model.BestRandomState(buffer, ShapeType(j), a, n, rnd)
                before := state.Energy()
                state = HillClimb(state, age).(*State)
                energy := state.Energy()

                if i == 0 && j == 1 || energy < bestEnergy {
                    vv("%dx random: %.6f -> %dx hill climb: %.6f\n", n, before, age, energy)
                    bestEnergy = energy
                    bestState = state
                }
            }
        }
    }

    return bestState
}

This is the parameters I used:

primitive -i src.jpg -o test0v1.svg -n 1000 -v -m 0

vs

primitive -i src.jpg -o test1v1.svg -n 1000 -v -m 1

Obviously the downside is that it take 5 times longer to get the result...

fogleman commented 7 years ago

But how does it compare to the original mode 0?

bmaltais commented 7 years ago

Let me run a quick test. I will add the result to the imgur post and report here.

bmaltais commented 7 years ago

OK. Updated the imgur post. Final score of original mode 0 (pure random) is 0.036257. So the final scores overall are:

Pick best shape mode 0: 0.032241 Orig mode 0: 0.036257 Mode 1: 0.034719

The funny thing is that mode 1 look the best to me... but score for new mode one is best.

Update:

Lowering the alpha parameter down to 100 actually improve significantly the result by allowing more layering.

fogleman commented 7 years ago

I guess the issue with the original mode 0 is that BestRandomShape isn't a good predictor of how well the shape will hill climb. I tested this hypothesis by tweaking this line:

https://github.com/fogleman/primitive/blob/master/primitive/model.go#L121

You can try something like 1, 100, 32 instead of 100, 100, 8 and get a better result.

Anyway, given 5x the processing time, I could probably get an even better score with some tweaking of these parameters. :) But I've been trying to balance quality with processing time so far...

bmaltais commented 7 years ago

Indeed, it does provide better result. But combined with the cycling through all shapes still provide the best results. I am thinking of removing the pass through circles and rectangles as those will be pretty much be approximated by elipses and rotated rectangles. This will cut down on time.

I am also testing an option where alpha value is being searched for the best match score. This is also improving the final score at the cost of speed.

fogleman commented 7 years ago

Yeah, I've searched on alpha before too. I prefer the look of a constant alpha though. I was thinking passing in alpha=0 could indicate doing a search on it.

bmaltais commented 7 years ago

That would be a great option. Another potential one could be to add the ability for ellipses to be rotated. Right now they are only horizontally or vertically stretched. Similar to the rotated rectangle mode.

fogleman commented 7 years ago

I implemented the alpha thing.

bmaltais commented 7 years ago

Nice. I will give it a try. You were right about the 1,100,32 change. It is almost as good as going through all the shapes. Probably not worth implementing.

Solido commented 7 years ago

Following the thread. Alpha as 0 is much welcome. Thx.

fogleman commented 7 years ago

@bmaltais Cool, I'll close for now.