Skip to content

Commit

Permalink
randomize findroom and add teleport early stop
Browse files Browse the repository at this point in the history
  • Loading branch information
guoyongzhi committed Jan 4, 2021
1 parent 36203b8 commit 042051f
Show file tree
Hide file tree
Showing 8 changed files with 95 additions and 53 deletions.
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
.ipynb_checkpoints
.vscode
res/*/*
res/*/*
address_compare
guxiang_animation
2 changes: 1 addition & 1 deletion Project.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name = "WordCloud"
uuid = "6385f0a0-cb03-45b6-9089-4e0acc74b26b"
authors = ["guoyongzhi <[email protected]>"]
version = "0.2.5"
version = "0.2.6"

[deps]
ColorSchemes = "35d6a980-a343-548e-a6ea-1d62b119f2f4"
Expand Down
22 changes: 15 additions & 7 deletions examples/compare.jl
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
using WordCloud

stwords = ["us", "will"];
println("Obama's")
println("==Obama's==")
cs = WordCloud.randomscheme()
as = WordCloud.randomangles()
fr = 0.6 #not too high
Expand All @@ -10,7 +10,7 @@ wca = wordcloud(
colors = cs,
angles = as,
filling_rate = fr) |> generate!
println("Trump's")
println("==Trump's==")
tb, wb = process(open("res/Donald Trump's Inaugural Address.txt"), stopwords=WordCloud.stopwords_en stwords)
samemask = tb .∈ Ref(wca.words)
println(sum(samemask), " same words")
Expand All @@ -37,21 +37,29 @@ for i in 1:length(tb)
WordCloud.QTree.setcenter!(wcb.qtrees[i], cxy)
end
end
println("ignore defferent words")
println("=ignore defferent words=")
ignore(wcb, .!samemask) do
generate!(wcb, 1000, patient=-1, retry=1) #patient=-1 means no teleport; retry=1 means no rescale
end
println("pin same words")
println("=pin same words=")
pin(wcb, samemask) do
placement!(wcb)
generate!(wcb, 1000, retry=1) #allow teleport but don‘t allow rescale
end
println("overall tuning")
generate!(wcb, 1000, patient=-1, retry=2) #allow rescale but don‘t allow teleport
if !iscompleted(wcb)
println("=overall tuning=")
generate!(wcb, 1000, patient=-1, retry=2) #allow rescale but don‘t allow teleport
end

ma = paint(wca)
mb = paint(wcb)
h,w = size(ma)
space = loadmask(shape(box, w÷20, h))
space .= WordCloud.ARGB(0,0,0,0)
WordCloud.ImageMagick.save("compare.png", [ma space mb])
try `mkdir address_compare`|>run catch end
WordCloud.ImageMagick.save("address_compare/compare.png", [ma space mb])

gif = WordCloud.GIF("address_compare")
record(wca, "Obama", gif)
record(wcb, "Trump", gif)
WordCloud.Render.generate(gif, framerate=0.5)
2 changes: 1 addition & 1 deletion src/WordCloud.jl
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
module WordCloud
export wordcloud, shape, ellipse, box, paint, loadmask, process,
train!, Momentum, generate!, generate_animation!, getposition
export record, parsecolor, placement!, imageof, bitor, take, ignore, pin
export record, parsecolor, placement!, imageof, bitor, take, ignore, pin, iscompleted
include("qtree.jl")
include("rendering.jl")
include("nlp.jl")
Expand Down
56 changes: 32 additions & 24 deletions src/interface.jl
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,12 @@ end

import ImageTransformations.imresize
"""
loadmask("res/heart.jpg")
loadmask("res/heart.jpg", 256, 256) #resize to 256*256
loadmask("res/heart.jpg", ratio=0.3) #scale 0.3
loadmask("res/heart.jpg", color="red", ratio=2) #set forecolor color
loadmask("res/heart.jpg", color="red", transparentcolor=(1,1,1)) #set forecolor color with transparentcolor
## examples
* loadmask("res/heart.jpg")
* loadmask("res/heart.jpg", 256, 256) #resize to 256*256
* loadmask("res/heart.jpg", ratio=0.3) #scale 0.3
* loadmask("res/heart.jpg", color="red", ratio=2) #set forecolor color
* loadmask("res/heart.jpg", color="red", transparentcolor=(1,1,1)) #set forecolor color with transparentcolor
"""
function loadmask(img::AbstractMatrix, args...; color=:original, backgroundcolor=:original, transparentcolor=:auto, kargs...)
if color!=:original || backgroundcolor!=:original
Expand Down Expand Up @@ -70,22 +71,22 @@ mutable struct wordcloud
end

"""
## kargs example
## kargs examples
### style kargs
colors = "black" #all same color
colors = ("black", (0.5,0.5,0.7), "yellow", "#ff0000", 0.2) #choose entries randomly
colors = ["black", (0.5,0.5,0.7), "yellow", "red", (0.5,0.5,0.7), 0.2, ......] #use entries sequentially in cycle
angles = 0 #all same angle
angles = (0, 90, 45) #choose entries randomly
angles = 0:180 #choose entries randomly
angles = [0, 22, 4, 1, 100, 10, ......] #use entries sequentially in cycle
filling_rate = 0.5
border = 1
* colors = "black" #all same color
* colors = ("black", (0.5,0.5,0.7), "yellow", "#ff0000", 0.2) #choose entries randomly
* colors = ["black", (0.5,0.5,0.7), "yellow", "red", (0.5,0.5,0.7), 0.2, ......] #use entries sequentially in cycle
* angles = 0 #all same angle
* angles = (0, 90, 45) #choose entries randomly
* angles = 0:180 #choose entries randomly
* angles = [0, 22, 4, 1, 100, 10, ......] #use entries sequentially in cycle
* filling_rate = 0.5
* border = 1
### mask kargs
mask = loadmask("res/heart.jpg", 256, 256) #see doc of `loadmask`
mask = loadmask("res/heart.jpg", color="red", ratio=2) #see doc of `loadmask`
mask = shape(ellipse, 800, 600, color="white", bgcolor=(0,0,0,0)) #see doc of `shape`
transparentcolor = ARGB32(0,0,0,0) #set the transparent color in mask
* mask = loadmask("res/heart.jpg", 256, 256) #see doc of `loadmask`
* mask = loadmask("res/heart.jpg", color="red", ratio=2) #see doc of `loadmask`
* mask = shape(ellipse, 800, 600, color="white", bgcolor=(0,0,0,0)) #see doc of `shape`
* transparentcolor = ARGB32(0,0,0,0) #set the transparent color in mask
"""
wordcloud(wordsweights::Tuple; kargs...) = wordcloud(wordsweights...; kargs...)
wordcloud(counter::AbstractDict; kargs...) = wordcloud(keys(counter)|>collect, values(counter)|>collect; kargs...)
Expand Down Expand Up @@ -157,11 +158,14 @@ function wordcloud(words::AbstractVector{<:AbstractString}, weights::AbstractVec
params[:border] = border
params[:font] = font
params[:minfontsize] = minfontsize
params[:completed] = false
params[:epoch] = 0
placement!(deepcopy(maskqtree), qtrees)
wordcloud(words, weights, imgs, mask, qtrees, maskqtree, params)
end
Base.getindex(wc::wordcloud, inds...) = wc.words[inds...]=>wc.weights[inds...]
Base.lastindex(wc::wordcloud) = lastindex(wc.words)
iscompleted(wc::wordcloud) = wc.params[:completed]
function getposition(wc)
msy, msx = getshift(wc.maskqtree)
pos = getshift.(wc.qtrees)
Expand All @@ -184,10 +188,10 @@ function paint(wc::wordcloud, file, args...; kargs...)
img
end

function record(wc::wordcloud, ep::Number, gif_callback=x->x)
function record(wc::wordcloud, label::AbstractString, gif_callback=x->x)
# @show size(n1)
resultpic = overlay!(paint(wc),
rendertextoutlines(string(ep), 32, color="black", linecolor="white", linewidth=1), 20, 20)
rendertextoutlines(label, 32, color="black", linecolor="white", linewidth=1), 20, 20)
gif_callback(resultpic)
end

Expand All @@ -203,12 +207,16 @@ function generate!(wc::wordcloud, nepoch::Number=100, args...; retry=3,
println("#$r. scale = $(wc.params[:scale])")
ep, nc = train_with_teleport!(wc.qtrees, wc.maskqtree, nepoch, args...;
trainer=trainer, optimiser=optimiser, patient=patient, krags...)
wc.params[:epoch] += ep
if nc == 0
break
end
end
@show ep, nc
if nc != 0
if nc == 0
wc.params[:completed] = true
else
wc.params[:completed] = false
colllist = first.(listcollision(wc.qtrees, wc.maskqtree))
get_text(i) = i>0 ? wc.words[i] : "#MASK#"
collwords = [(get_text(i), get_text(j)) for (i,j) in colllist]
Expand All @@ -227,8 +235,8 @@ function generate_animation!(wc::wordcloud, args...; outputdir="gifresult", over
end
try `mkdir $(outputdir)`|>run catch end
gif = GIF(outputdir)
record(wc, 0, gif)
re = generate!(wc, args...; callbackstep=callbackstep, callbackfun=ep->record(wc, ep, gif), kargs...)
record(wc, "0", gif)
re = generate!(wc, args...; callbackstep=callbackstep, callbackfun=ep->record(wc, string(ep), gif), kargs...)
Render.generate(gif)
re
end
Expand Down
31 changes: 20 additions & 11 deletions src/qtreetools.jl
Original file line number Diff line number Diff line change
Expand Up @@ -137,12 +137,20 @@ function findroom(ground, q=[(levelnum(ground), 1, 1)])
end
while !isempty(q)
i = popfirst!(q)
for cn in shuffle4()
ci = child(i, cn)
if ground[ci] == EMPTY
return ci
elseif ground[ci] == HALF
push!(q, ci)
if i[1] == 1
if ground[i] == EMPTY return i end
else
for cn in shuffle4()
ci = child(i, cn)
if ground[ci] == EMPTY
if rand() < 0.7 #避免每次都是局部最优
return ci
else
push!(q, ci)
end
elseif ground[ci] == HALF
push!(q, ci)
end
end
end
end
Expand Down Expand Up @@ -200,16 +208,17 @@ end

"将sortedtrees依次叠加到ground上,同时修改sortedtrees的shift"
function placement!(ground, sortedtrees)
pos = Vector{Tuple{Int, Int, Int}}()
# pos = Vector{Tuple{Int, Int, Int}}()
for t in sortedtrees
ind = placement!(ground, t)
overlap!(ground, t)
if ind === nothing
return pos
end
push!(pos, ind)
# push!(pos, ind)
end
return pos
nothing
# return pos
end

function placement!(ground, qtree::ShiftedQtree)
Expand All @@ -233,8 +242,8 @@ function placement!(ground, sortedtrees, index::Number)
end
overlap!(ground, sortedtrees[i])
end
ind = placement!(ground, sortedtrees[index])
return ind
placement!(ground, sortedtrees[index])
# return ind
end
function placement!(ground, sortedtrees, indexes)
for i in 1:length(sortedtrees)
Expand Down
13 changes: 7 additions & 6 deletions src/rendering.jl
Original file line number Diff line number Diff line change
Expand Up @@ -142,9 +142,10 @@ schemes = [schemes_colorbrewer..., schemes_seaborn...]

"""
get box or ellipse image
shape(box, 80, 50) #80*50 box
shape(box, 80, 50, 4) #box with cornerradius=4
shape(ellipse, 80, 50, color="red") #80*50 red ellipse
## Examples
* shape(box, 80, 50) #80*50 box
* shape(box, 80, 50, 4) #box with cornerradius=4
* shape(ellipse, 80, 50, color="red") #80*50 red ellipse
"""
function shape(shape_, width, height, args...; color="white", bgcolor=(0,0,0,0))
Drawing(width, height, :image)
Expand All @@ -163,11 +164,11 @@ function gif_callback_factory()
counter = Iterators.Stateful(0:typemax(Int))
pic->save(gifdirectory*@sprintf("/%010d.png", popfirst!(counter)), pic)
end
function try_gif_gen(gifdirectory)
function try_gif_gen(gifdirectory; framerate=4)
try
pipeline(`ffmpeg -f image2 -i $(gifdirectory)/%010d.png -vf
palettegen -y $(gifdirectory)/result-palette.png`, stdout=devnull, stderr=devnull) |> run
pipeline(`ffmpeg -framerate 4 -f image2 -i $(gifdirectory)/%010d.png
pipeline(`ffmpeg -framerate $(framerate) -f image2 -i $(gifdirectory)/%010d.png
-i $(gifdirectory)/result-palette.png -lavfi paletteuse -y $(gifdirectory)/result.gif`,
stdout=devnull, stderr=devnull) |> run
catch e
Expand All @@ -183,5 +184,5 @@ function GIF(directory)
end
Base.push!(gif::GIF, img) = ImageMagick.save(gif.directory*@sprintf("/%010d.png", popfirst!(gif.counter)), img)
(gif::GIF)(img) = Base.push!(gif, img)
generate(gif::GIF) = try_gif_gen(gif.directory)
generate(gif::GIF, args...; kargs...) = try_gif_gen(gif.directory, args...; kargs...)
end
18 changes: 16 additions & 2 deletions src/train.jl
Original file line number Diff line number Diff line change
Expand Up @@ -331,6 +331,8 @@ function train_with_teleport!(ts, maskqt, nepoch::Number, args...;
nc = 0
count = 0
nc_min = Inf
teleport_count = 0
last_cinds = nothing
while ep < nepoch
# @show "##", ep, nc, length(collpool), (count,nc_min)
nc = trainer(ts, maskqt, args...; collpool=collpool, queue=queue, kargs...)
Expand All @@ -343,15 +345,27 @@ function train_with_teleport!(ts, maskqt, nepoch::Number, args...;
if nc != 0 && length(collpool)>0 && patient >0 && (count >= patient || count > length(collpool)) #超出耐心或少数几个碰撞
nc_min = nc
cinds = teleport!(ts, maskqt, collpool=collpool)
println("@epoch $ep, count $count collision $nc($(length(collpool))) teleport $cinds")
println("@epoch $ep, count $count collision $nc($(length(collpool))) teleport $cinds to $(getshift.(ts[cinds]))")
count = 0
cinds_set = Set(cinds)
if last_cinds == cinds_set
teleport_count += 1
else
teleport_count = 0
end
last_cinds = cinds_set

end
if callbackstep>0 && ep%callbackstep==0
callbackfun(ep)
end
if nc == 0
return ep, nc
end
if patient > 0 && teleport_count >= patient
println("The teleport strategy failed after $ep epochs")
return ep, nc
end
end
ep, nc
end
end

0 comments on commit 042051f

Please sign in to comment.