feat: Display divided image in greyscale

This commit is contained in:
Leni Aniva 2025-04-14 13:12:45 -07:00
parent 6d2df0e84f
commit a189981d4e
Signed by: aniva
GPG Key ID: 4D9B1C8D10EA4C50
1 changed files with 78 additions and 11 deletions

View File

@ -1,5 +1,14 @@
using Base
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
@kwdef struct Rect
@ -16,41 +25,53 @@ function aspect_ratio(r::Rect)::Real
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
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}
remainder = Rect[Rect(pos=(1,1), size=size(img), color=mean(img))]
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 = [Region(pos=(1,1), size=size(img), dir=false)]
result = Rect[]
# Loop until the entire field is filled
while length(remainder) > 0
section = pop!(remainder)
width = size_min
height = size_min
(px, py) = section.pos
(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
while width < section.size[1] || height < section.size[2]
subimg = img[section.pos[1]:section.pos[1]+width-1, section.pos[2]:section.pos[2]+height-1]
while width < width_max || height < height_max
subimg = img[px:px+width-1, py:py+height-1]
if std(subimg) >= threshold_std
break
end
colour = mean(subimg)
ar = width / height
if width < section.size[1] && ar < threshold_aspect
if width < width_max && ar < threshold_aspect
width += 1
elseif height < section.size[1]
elseif height < height_max && ar > 1/threshold_aspect
height += 1
else
break
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(
pos=section.pos,
size=(width, height),
@ -58,8 +79,54 @@ function divide_image(img::Matrix{}, size_min::Int=16, size_max::Int=256, thresh
)
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
return result
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