Stock composition version #1
|
@ -1,5 +1,14 @@
|
||||||
using Base
|
using Base
|
||||||
using Statistics, Images
|
using Statistics, Images
|
||||||
|
import Luxor as L
|
||||||
|
|
||||||
|
@kwdef struct Region
|
||||||
|
pos::Tuple{Int,Int}
|
||||||
|
size::Tuple{Int,Int}
|
||||||
|
# If true, this region increases from x to y. This direction variable steers
|
||||||
|
# the direction of cut.
|
||||||
|
dir::Bool
|
||||||
|
end
|
||||||
|
|
||||||
# Time-dependent packing
|
# Time-dependent packing
|
||||||
@kwdef struct Rect
|
@kwdef struct Rect
|
||||||
|
@ -16,41 +25,53 @@ function aspect_ratio(r::Rect)::Real
|
||||||
end
|
end
|
||||||
|
|
||||||
"""
|
"""
|
||||||
divide_image(img::BitMatrix, size_min::Int=16, size_max::Int=256)
|
divide_image(img::Matrix{}, size_min::Int=16, size_max::Int=256)
|
||||||
|
|
||||||
Divides an image into rectangles of the same colour. The rectangles are not
|
Divides an image into rectangles of the same colour. The rectangles are not
|
||||||
allowed to have extreme aspect ratios. There is a minimal size of each retangle.
|
allowed to have extreme aspect ratios. There is a minimal size of each retangle.
|
||||||
"""
|
"""
|
||||||
function divide_image(img::Matrix{}, size_min::Int=16, size_max::Int=256, threshold_aspect::Real=3.0, threshold_std::Real=0.4)::Array{Rect}
|
function divide_image(img::Matrix{}; size_min::Int=16, size_max::Int=128, threshold_aspect::Real=3.0, threshold_std::Real=0.4)::Array{Rect}
|
||||||
remainder = Rect[Rect(pos=(1,1), size=size(img), color=mean(img))]
|
remainder = [Region(pos=(1,1), size=size(img), dir=false)]
|
||||||
result = Rect[]
|
result = Rect[]
|
||||||
|
|
||||||
# Loop until the entire field is filled
|
# Loop until the entire field is filled
|
||||||
while length(remainder) > 0
|
while length(remainder) > 0
|
||||||
section = pop!(remainder)
|
section = pop!(remainder)
|
||||||
|
|
||||||
width = size_min
|
(px, py) = section.pos
|
||||||
height = size_min
|
(sx, sy) = section.size
|
||||||
|
|
||||||
|
@assert px + sx - 1 <= size(img)[1]
|
||||||
|
@assert py + sy - 1 <= size(img)[2]
|
||||||
|
|
||||||
|
width = 1
|
||||||
|
height = 1
|
||||||
|
|
||||||
|
width_max = min(sx, size_max)
|
||||||
|
height_max = min(sy, size_max)
|
||||||
|
|
||||||
# Try to expand this rectangle to the maximum size
|
# Try to expand this rectangle to the maximum size
|
||||||
|
|
||||||
while width < section.size[1] || height < section.size[2]
|
while width < width_max || height < height_max
|
||||||
subimg = img[section.pos[1]:section.pos[1]+width-1, section.pos[2]:section.pos[2]+height-1]
|
subimg = img[px:px+width-1, py:py+height-1]
|
||||||
if std(subimg) >= threshold_std
|
if std(subimg) >= threshold_std
|
||||||
break
|
break
|
||||||
end
|
end
|
||||||
colour = mean(subimg)
|
colour = mean(subimg)
|
||||||
ar = width / height
|
ar = width / height
|
||||||
|
|
||||||
if width < section.size[1] && ar < threshold_aspect
|
if width < width_max && ar < threshold_aspect
|
||||||
width += 1
|
width += 1
|
||||||
elseif height < section.size[1]
|
elseif height < height_max && ar > 1/threshold_aspect
|
||||||
height += 1
|
height += 1
|
||||||
else
|
else
|
||||||
break
|
break
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
subimg = img[section.pos[1]:section.pos[1]+width-1, section.pos[2]:section.pos[2]+height-1]
|
@assert width <= sx
|
||||||
|
@assert height <= sy
|
||||||
|
|
||||||
|
subimg = img[px:px+width-1, py:py+height-1]
|
||||||
rect = Rect(
|
rect = Rect(
|
||||||
pos=section.pos,
|
pos=section.pos,
|
||||||
size=(width, height),
|
size=(width, height),
|
||||||
|
@ -58,8 +79,54 @@ function divide_image(img::Matrix{}, size_min::Int=16, size_max::Int=256, thresh
|
||||||
)
|
)
|
||||||
push!(result, rect)
|
push!(result, rect)
|
||||||
|
|
||||||
# FIXME: Add next iteration region
|
if section.dir
|
||||||
|
if width < sx
|
||||||
|
push!(remainder, Region(
|
||||||
|
pos=(px + width, py),
|
||||||
|
size=(sx - width, height),
|
||||||
|
dir=false,
|
||||||
|
))
|
||||||
|
end
|
||||||
|
if height < sy
|
||||||
|
push!(remainder, Region(
|
||||||
|
pos=(px, py + height),
|
||||||
|
size=(sx, sy - height),
|
||||||
|
dir=true,
|
||||||
|
))
|
||||||
|
end
|
||||||
|
else
|
||||||
|
if height < sy
|
||||||
|
push!(remainder, Region(
|
||||||
|
pos=(px, py + height),
|
||||||
|
size=(width, sy - height),
|
||||||
|
dir=true,
|
||||||
|
))
|
||||||
|
end
|
||||||
|
if width < sx
|
||||||
|
push!(remainder, Region(
|
||||||
|
pos=(px + width, py),
|
||||||
|
size=(sx - width, sy),
|
||||||
|
dir=false,
|
||||||
|
))
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
return result
|
return result
|
||||||
end
|
end
|
||||||
|
|
||||||
|
"""
|
||||||
|
draw_rect(size::Tuple{Int, Int}, rects::Array{Rect})
|
||||||
|
|
||||||
|
Displays the divided image in greyscale.
|
||||||
|
"""
|
||||||
|
function draw_rect(size::Tuple{Int, Int}, rects::Array{Rect})
|
||||||
|
L.Drawing(size[1], size[2], :png)
|
||||||
|
L.background("black")
|
||||||
|
for rect in rects
|
||||||
|
c = N0f8(rect.color)
|
||||||
|
setcolor(c, c, c)
|
||||||
|
L.rect(L.Point(rect.pos), rect.size[1], rect.size[2], action = :fill)
|
||||||
|
end
|
||||||
|
L.finish()
|
||||||
|
end
|
||||||
|
|
Loading…
Reference in New Issue