Skip to content

Commit

Permalink
clean up history & bug fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
guoyongzhi committed Mar 8, 2021
1 parent ed1ab71 commit f13dc34
Show file tree
Hide file tree
Showing 13 changed files with 103 additions and 85 deletions.
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,10 @@ paint(wc, "alice.png", ratio=0.5, background=outline(wc.mask, color="purple", li
![animation](res/animation.gif)
[Training animation](./examples/animation.jl)
*Run the command `runexample(:animation)` or `showexample(:animation)` to get the result.*
## Specifying the style of a particular word
![specifiedstyle](res/specifiedstyle.png)
[Speciying the style of a particular word](./examples/specifiedstyle.jl)
*Run the command `runexample(:specifiedstyle)` or `showexample(:specifiedstyle)` to get the result.*
## Gathering style
![gathering](res/gathering.png)
[gathering style](./examples/gathering.jl)
*Run the command `runexample(:gathering)` or `showexample(:gathering)` to get the result.*
## Comparison
![compare](res/compare.png)
[Comparison of Obama's and Trump's inaugural address](./examples/compare.jl)
Expand Down
12 changes: 7 additions & 5 deletions examples/中文.jl
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,12 @@ jieba.add_word("英特纳雄耐尔")
wc = wordcloud(
processtext(jieba.lcut(TheInternationale)),
colors = "#DE2910",
mask = WordCloud.randommask("#FFDE00", 400),
density=0.65)|>generate!
println("结果保存在 中文.svg")
paint(wc, "中文.svg")
# mask = WordCloud.randommask("#FFDE00", 400),
mask = loadmask(pkgdir(WordCloud)*"/res/heart_mask.png", color="#FFDE00"),
density=0.65) |> generate!

println("结果保存在 中文.png")
paint(wc, "中文.png")
wc
#eval# runexample(:中文)
#md# ![](中文.svg)
#md# ![](中文.png)
Binary file added res/gathering.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added res/heart_mask.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
12 changes: 7 additions & 5 deletions src/qtree.jl
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
module QTree
export AbstractStackedQtree, StackedQtree, ShiftedQtree, buildqtree!,
shift!, setrshift!, setcshift!, setshift!, getshift, getcenter, setcenter!,
collision, collision_bfs, collision_bfs_rand, listcollision,
findroom_rand, findroom_gathering, levelnum, outofbounds, kernelsize, placement!, decode
collision, collision_bfs, collision_bfs_rand, batchcollision,
findroom_uniform, findroom_gathering, levelnum, outofbounds, kernelsize, placement!, decode

using Random
using Combinatorics
Expand Down Expand Up @@ -206,7 +206,7 @@ function shift!(t::ShiftedQtree, l::Integer, st1::Integer, st2::Integer)
end
buildqtree!(t, l + 1)
end
shift!(t::ShiftedQtree, l::Integer, st::Tuple{Integer,Integer}) = shift!(t, l, st...)
shift!(t::ShiftedQtree, l::Integer, st::Tuple{Integer, Integer}) = shift!(t, l, st...)
function setshift!(t::ShiftedQtree, l::Integer, st1::Integer, st2::Integer)
for i in l:-1:1
setrshift!(t[i], st1)
Expand All @@ -216,11 +216,13 @@ function setshift!(t::ShiftedQtree, l::Integer, st1::Integer, st2::Integer)
end
buildqtree!(t, l + 1)
end
setshift!(t::ShiftedQtree, l::Integer, st::Tuple{Integer,Integer}) = setshift!(t, l, st...)
setshift!(t::ShiftedQtree, st::Tuple{Integer,Integer}) = setshift!(t, 1, st)
setshift!(t::ShiftedQtree, l::Integer, st::Tuple{Integer, Integer}) = setshift!(t, l, st...)
setshift!(t::ShiftedQtree, st::Tuple{Integer, Integer}) = setshift!(t, 1, st)
getshift(t::ShiftedQtree, l::Integer=1) = getshift(t[l])
kernelsize(t::ShiftedQtree, l::Integer=1) = kernelsize(t[l])
getcenter(t::ShiftedQtree) = getshift(t) .+ kernelsize(t) 2
getcenter(l::Integer, a::Integer, b::Integer) = l == 1 ? (a, b) : (2^(l-1)*(a-1)+2^(l-2), 2^(l-1)*(b-1)+2^(l-2))
getcenter(ind::Tuple{Integer, Integer, Integer}) = getcenter(ind...)
callefttop(t::ShiftedQtree, center) = center .- kernelsize(t) 2
setcenter!(t::ShiftedQtree, center) = setshift!(t, callefttop(t, center))
function inbounds(bgqt::ShiftedQtree, qt::ShiftedQtree)
Expand Down
51 changes: 25 additions & 26 deletions src/qtreetools.jl
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ function collision_bfs_rand(Q1::AbstractStackedQtree, Q2::AbstractStackedQtree,
end

ColItemType = Pair{Tuple{Int,Int},Tuple{Int,Int,Int}}
function listcollision_native(qtrees::AbstractVector, mask::AbstractStackedQtree,
function batchcollision_native(qtrees::AbstractVector, mask::AbstractStackedQtree,
indpairs::Vector{<:Union{Vector, Tuple}}; collist=Vector{ColItemType}(),
queue=Vector{Tuple{Int,Int,Int}}(), at=(levelnum(qtrees[1]), 1, 1))
getqtree(i) = i==0 ? mask : qtrees[i]
Expand All @@ -104,7 +104,7 @@ function listcollision_native(qtrees::AbstractVector, mask::AbstractStackedQtree
end
collist
end
function listcollision_native(qtrees::AbstractVector, mask::AbstractStackedQtree,
function batchcollision_native(qtrees::AbstractVector, mask::AbstractStackedQtree,
indpairs::Vector{Tuple{Tuple{Int,Int},Tuple{Int,Int,Int}}}; collist=Vector{ColItemType}(),
queue=Vector{Tuple{Int,Int,Int}}())
getqtree(i) = i==0 ? mask : qtrees[i]
Expand All @@ -118,18 +118,18 @@ function listcollision_native(qtrees::AbstractVector, mask::AbstractStackedQtree
end
collist
end
function listcollision_native(qtrees::AbstractVector, mask::AbstractStackedQtree,
function batchcollision_native(qtrees::AbstractVector, mask::AbstractStackedQtree,
inds=0:length(qtrees); collist=Vector{ColItemType}(),
queue=Vector{Tuple{Int,Int,Int}}(), at=(levelnum(qtrees[1]), 1, 1))
indpairs = combinations(inds, 2) |> collect |> shuffle!
listcollision_native(qtrees, mask, indpairs, collist=collist, at=at)
batchcollision_native(qtrees, mask, indpairs, collist=collist, at=at)
end
function listcollision_native(qtrees::AbstractVector, mask::AbstractStackedQtree,
function batchcollision_native(qtrees::AbstractVector, mask::AbstractStackedQtree,
inds::AbstractSet; kargs...)
listcollision_native(qtrees, mask, inds|>collect; kargs...)
batchcollision_native(qtrees, mask, inds|>collect; kargs...)
end

function findroom_rand(ground, q=[(levelnum(ground), 1, 1)])
function findroom_uniform(ground, q=[(levelnum(ground), 1, 1)])
if isempty(q)
push!(q, (levelnum(ground), 1, 1))
end
Expand Down Expand Up @@ -253,6 +253,7 @@ end
"将sortedtrees依次叠加到ground上,同时修改sortedtrees的shift"
function placement!(ground, sortedtrees; kargs...)
# pos = Vector{Tuple{Int, Int, Int}}()
ind = nothing
for t in sortedtrees
ind = placement!(ground, t; kargs...)
overlap!(ground, t)
Expand All @@ -261,21 +262,17 @@ function placement!(ground, sortedtrees; kargs...)
end
# push!(pos, ind)
end
nothing
ind
# return pos
end

function placement!(ground, qtree::ShiftedQtree; roomfinder=findroom_rand, kargs...)
function placement!(ground, qtree::ShiftedQtree; roomfinder=findroom_uniform, kargs...)
ind = roomfinder(ground; kargs...)
# @show ind
if ind === nothing
return nothing
end
l, r, c = ind
x = floor(2^(l - 1) * (r - 1) + 2^(l - 2))
y = floor(2^(l - 1) * (c - 1) + 2^(l - 2))
m, n = kernelsize(qtree[1])
setshift!(qtree, 1, x - m ÷ 2, y - n ÷ 2) # 居中
setcenter!(qtree, getcenter(ind)) # 居中
return ind
end

Expand All @@ -296,11 +293,13 @@ function placement!(ground, sortedtrees, indexes; kargs...)
end
overlap!(ground, sortedtrees[i])
end
ind = nothing
for i in indexes
placement!(ground, sortedtrees[i]; kargs...)
ind = placement!(ground, sortedtrees[i]; kargs...)
if ind === nothing return ind end
overlap!(ground, sortedtrees[i])
end
nothing
ind
end

function locate(qt::AbstractStackedQtree, ind::Tuple{Int, Int, Int}=(levelnum(qt), 1, 1))
Expand Down Expand Up @@ -367,7 +366,7 @@ function locate!(qts::AbstractVector, inds::Union{AbstractVector{Int}, AbstractS
end


function listcollision_qtree(qtrees::AbstractVector, mask::AbstractStackedQtree, loctree::QtreeNode;
function batchcollision_qtree(qtrees::AbstractVector, mask::AbstractStackedQtree, loctree::QtreeNode;
collist = Vector{ColItemType}(),
queue = Vector{Tuple{Int, Int, Int}}(),
)
Expand All @@ -379,12 +378,12 @@ function listcollision_qtree(qtrees::AbstractVector, mask::AbstractStackedQtree,
# @show length(loctree.value.loc), length(loctree.value.cumloc)
indpairs = combinations(loctree.value.loc, 2) |> collect
indpairs = [(min(p...), max(p...)) for p in indpairs] |> shuffle!
listcollision_native(qtrees, mask, indpairs, collist=collist, queue=queue, at=loctree.value.ind)
batchcollision_native(qtrees, mask, indpairs, collist=collist, queue=queue, at=loctree.value.ind)
end
if length(loctree.value.loc) > 0 && length(loctree.value.cumloc) > 0
indpairs = Iterators.product(loctree.value.cumloc, loctree.value.loc) |> collect |> vec
indpairs = [(min(p...), max(p...)) for p in indpairs] |> shuffle!
listcollision_native(qtrees, mask, indpairs, collist=collist, queue=queue, at=loctree.value.ind)
batchcollision_native(qtrees, mask, indpairs, collist=collist, queue=queue, at=loctree.value.ind)
end
for c in loctree.children
if c !== nothing
Expand All @@ -394,21 +393,21 @@ function listcollision_qtree(qtrees::AbstractVector, mask::AbstractStackedQtree,
end
collist
end
function listcollision_qtree(qtrees::AbstractVector, mask::AbstractStackedQtree; kargs...)
function batchcollision_qtree(qtrees::AbstractVector, mask::AbstractStackedQtree; kargs...)
loctree = locate!(qtrees)
loctree = locate!(mask, loctree, label=0, newnode=LocQtreeInt)
listcollision_qtree(qtrees, mask, loctree; kargs...)
batchcollision_qtree(qtrees, mask, loctree; kargs...)
end
function listcollision_qtree(qtrees::AbstractVector, mask::AbstractStackedQtree, inds::Union{AbstractVector{Int}, AbstractSet{Int}}; kargs...)
function batchcollision_qtree(qtrees::AbstractVector, mask::AbstractStackedQtree, inds::Union{AbstractVector{Int}, AbstractSet{Int}}; kargs...)
loctree = locate!(qtrees, inds)
loctree = locate!(mask, loctree, label=0, newnode=LocQtreeInt)
listcollision_qtree(qtrees, mask, loctree; kargs...)
batchcollision_qtree(qtrees, mask, loctree; kargs...)
end

function listcollision(qtrees::AbstractVector, mask::AbstractStackedQtree, args...; kargs...)
function batchcollision(qtrees::AbstractVector, mask::AbstractStackedQtree, args...; kargs...)
if length(qtrees) > 25
return listcollision_qtree(qtrees, mask, args...; kargs...)
return batchcollision_qtree(qtrees, mask, args...; kargs...)
else
return listcollision_native(qtrees, mask, args...; kargs...)
return batchcollision_native(qtrees, mask, args...; kargs...)
end
end
4 changes: 2 additions & 2 deletions src/rendering.jl
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ using Luxor
using Colors
using ColorSchemes
using ImageMagick
import ImageTransformations.filter
import ImageTransformations.imresize

save = Luxor.FileIO.save

Expand Down Expand Up @@ -225,7 +225,7 @@ schemes_seaborn = filter(s -> occursin("seaborn", colorschemes[s].category), col
schemes = [schemes_colorbrewer..., schemes_seaborn...]

"""
get box or ellipse image
get a box or ellipse svg image
## Examples
* shape(box, 80, 50) #80*50 box
* shape(box, 80, 50, 4) #box with cornerradius=4
Expand Down
20 changes: 10 additions & 10 deletions src/strategy.jl
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,13 @@ function feelingoccupied(imgs, border=0, bgvalue=imgs[1][1])
sum(s) - er
end

function textoccupied(words, fontsizes, fonts; border=0)
function textoccupied(words, fontsizes, fonts)
border=1
imgs = []
for (c, sz, ft) in zip(words, fontsizes, fonts)
# print(c)
img = Render.rendertext(string(c), sz, backgroundcolor=(0,0,0,0),font=ft, border=border)
push!(imgs, wordmask(img, (0,0,0,0), border))
img = Render.rendertext(string(c), sz, backgroundcolor=(0,0,0,0), font=ft, border=border)
push!(imgs, img)
end
feelingoccupied(imgs, border) #border>0 以获取背景色imgs[1]
end
Expand Down Expand Up @@ -57,7 +58,7 @@ function preparebackground(img, bgcolor)
return img, maskqt, groundsize, groundoccupied
end

function prepareword(word, fontsize, color, angle, groundsize; backgroundcolor=(0,0,0,0), font="", border=0)
function prepareword(word, fontsize, color, angle; backgroundcolor=(0,0,0,0), font="", border=0)
rendertext(string(word), fontsize, color=color, backgroundcolor=backgroundcolor,
angle=angle, border=border, font=font, type=:both)
end
Expand All @@ -66,17 +67,17 @@ wordmask(img, bgcolor, border) = dilate(img.!=img[1], border)
#https://github.com/JuliaGraphics/Luxor.jl/issues/107

## weight_scale
function cal_weight_scale(words, fontsizes, fonts, target, initialscale; kargs...)
function cal_weight_scale(words, fontsizes, fonts, target, initialscale)
input = initialscale
output = textoccupied(words, fontsizes, fonts; kargs...)
output = textoccupied(words, fontsizes, fonts)
return output, sqrt(target/output) * input# 假设output=k*input^2
end

function find_weight_scale!(wc::WC; initialscale=0, density=0.3, maxiter=5, error=0.05, kargs...)
function find_weight_scale!(wc::WC; initialscale=0, density=0.3, maxiter=5, error=0.05)
ground_size = wc.params[:groundoccupied]
words = wc.words
if initialscale <= 0
initialscale = (ground_size/length(words)/0.4*density)
initialscale = (ground_size/length(words)/0.4*density) #初始值假设字符的字面框面积占正方格比率为0.4(低估了汉字)
end
@assert sum(wc.weights.^2 .* length.(words)) / length(wc.weights) 1.0
target_lower = (density - error) * ground_size
Expand All @@ -91,8 +92,7 @@ function find_weight_scale!(wc::WC; initialscale=0, density=0.3, maxiter=5, erro
break
end
wc.params[:scale] = sc
tg, sc = cal_weight_scale(words, getfontsizes(wc, words), fonts,
density*ground_size, sc; kargs...)
tg, sc = cal_weight_scale(words, getfontsizes(wc, words), fonts, density*ground_size, sc)
println("scale=$(wc.params[:scale]), density=$(tg/ground_size)")
if target_lower <= tg <= target_upper
break
Expand Down
Loading

0 comments on commit f13dc34

Please sign in to comment.