Skip to content

Instantly share code, notes, and snippets.

@Oldes
Last active March 23, 2023 23:50
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Oldes/4b75133736ee548e96570e269621a445 to your computer and use it in GitHub Desktop.
Save Oldes/4b75133736ee548e96570e269621a445 to your computer and use it in GitHub Desktop.
Reproducing images with geometric primitives. Using curves.
REBOL [
Title: "Reproducing images with geometric primitives."
type: module
name: primitive
date: 24-Mar-2023
author: "Oldes"
version: 0.2.0
license: MIT
purpose: {This is a try to have something like this https://github.com/fogleman/primitive}
exports: [primitivize]
needs: [3.10.5 blend2d]
usage: [primitivize/with %source.jpg [max-steps 2000 seed 12 save %result.jpg]]
]
primitivize: function [
source [image! file!]
/with options [block!]
][
unless image? source [ source: load :source ]
if source/size/x > 256 [ source: resize source 256 ]
size: source/size
output: make image! size
temp1: make image! size
temp2: make image! size
;; initial image difference
dif: image-diff source output
max-radius: 100
max-steps: 1000
max-similarity: 1%
mod-radius: 0.9
line-width: 30
out-file: none
alpha: 0.7
step: 0
scale: 600%
if options [
parse options [any [
'max-radius set v: number! (max-radius: v)
| 'mod-radius set v: number! (mod-radius: min v 1.0)
| 'max-steps set v: number! (max-steps: v)
| 'max-similarity set v: number! (max-similarity: v)
| 'alpha set v: number! (alpha: min v 1.0)
| 'scale set v: number! (scale: v)
| 'seed set v: skip (random/seed :v)
| 'save set v: file! (out-file: v)
| skip
]]
]
commands: [
pen (clr)
line-cap 2 2 ;= rounded ends
line-width (line-width * (1.1 - (step / max-steps)))
shape [
move (pos)
curv (pos - (as-pair random max-radius random max-radius) + (as-pair random max-radius random max-radius))
(pos - (as-pair random max-radius random max-radius) + (as-pair random max-radius random max-radius))
]
]
all-commands: make block! max-steps * 9
until [
pos: random size
clr: pick source pos
;; drawing with reduced opacity
clr/4: alpha * clr/4
;; draw 2 versions and use the one with better result
change temp1 output
change temp2 output
draw temp1 c1: compose/deep commands
draw temp2 c2: compose/deep commands
;? c1
d1: image-diff source temp1
d2: image-diff source temp2
;print ["diffs:" d1 tab d2]
either any [
d1 < dif
d2 < dif
][
++ step
;; Use the better version as a new output and store its draw commands,
;; so the image may be later be redrawn in a higher resolution.
dif: either d1 < d2 [
change output temp1
append append all-commands 'scale scale
append append all-commands c1 'reset-matrix
;probe c1
d1
][
change output temp2
append append all-commands 'scale scale
append append all-commands c2 'reset-matrix
;probe c2
d2
]
print ["Step:" step " with diff:" dif]
;; lower the maximum size of objects with increased steps..
;; (initially drawing larger objects and then smaller and smaller)
max-radius: 100 * (1.1 - (step / max-steps))
][
;; None of the new versions have better result!
;; Try smaller object where is better chance to have improved similarity.
max-radius: max-radius * mod-radius
if max-radius < 1 [
;; If still not able to improve the output, then reduce line width,
;; so there is better chance to improve the image
line-width: line-width * 0.5
;; reset the max-radius as well
max-radius: 100 * (1.1 - (step / max-steps))
]
]
;; stop continuation if...
any [
step = max-steps ;; maximum number of primitives reached
dif < max-similarity ;; or the output image is already good enough
]
]
;; Use collected draw commands scaled...
save %result-scaled.jpg draw scale * size all-commands
;; Save the original output result...
if out-file [
try/except [
save out-file output
][ print ["Failed to save file:" out-file] ]
]
output
]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment