Thank you for the script. though It could probably use some reformatting and extra comments.
First the shade of a circle to radius is non-linear, but a squared effect. radius^2 -> area
Also note that for pure black the circles shoudl have a diameter of the 'tile' they occupy. That however means the circle will 'overlap' the neighbouring circles, which means that a linear increase in circle size no longer means a square increase in 'density' or 'represented shade'. Anyone know the actual formula that takes this overlay change into account?
You said one of your 'slow' parts was "use harddisk to store small image patches"
On solution is first pixelate your image into squares of the appropriate grayscale shade.
See example in: Photo handling... Protect Someone's Anonymity
http://www.imagemagick.org/Usage//photos/#anonymity
You can then use a 'dither' solution to replace each square of a specific shade with a circle of the right size.
At no time is the image then broken into small pieces.
Hmmmm...
Given your original 'face' as "face_orig.jpg", and using the largest orthogonal halftone circles "h16x16o" which is based on a 16x16 pixel tiles
The image is 480x409, whcih is not a multiple of 16, so I'll first crop it to 480x400 which is a multiple of 16. dividing that by 16 gives 30x25 so the pixelation size is that size.
Code: Select all
convert face_orig.jpg -colorspace gray -crop 480x400+0+0 +repage \
-resize 30x25 -scale 1600% face_pixelated.png
Now ordered-dither that...
Code: Select all
convert face_pixelated.png -ordered-dither h16x16o face_od16.gif
As you can see it works, and also handles black properly (when circles overlap).
However if anti-aliased circles is needed you can DIY the ordered dither by using a lookup sequence of circle image. For example something like shown in...
Dithering with Symbol Patterns
http://www.imagemagick.org/Usage/quantize/#diy_symbols
except each pattern is just a circle image.
Hmmmm, generating the same tile size as previously, and ignoring the non-linear overlap of circles
Code: Select all
for i in `seq 0 11`; do
j=`expr $i + 7`
convert -size 16x16 xc: -draw "circle 7.5,7.5 7.5,$j.5" miff:-
done | convert - circle_array.gif
Here is the results if you can't get the above to work
circle_array.gif
Of course web browsers would mistake this GIF array of images as an animation
just to see this array...
Code: Select all
convert circle_array.gif +append circle_list.gif
Of course you can make a longer array by using non-integer radius but for our testing purpose this will do.
Now lets do a DIY symbol dither, where each pixel shade is used to index the right image for the circle representing it. The 11.9999 is for the 12 images in the array.
Code: Select all
convert face_pixelated.png -negate \
circle_array.gif -virtual-pixel tile -fx 'u[floor(11.9999*u)+1]' \
face_circles.gif
Of course as FX is being used this can be very slow but it works!
a 3 times speed up, would be to only use FX on one channel only.
See IM Examples FX
http://www.imagemagick.org/Usage/transform/#fx
Also remember the a linear radius was used rather than a radius squared shading, and no attempt to handle overlap shade modifications was done. This is a starting point! Lets see what you and others can do with it
If everything can be worked it it is posible that this could be built it for speed!!!!
PS: how to apply this to generate a angled pixelated tiling, to get a proper offset halftone of color is going to be a real challenge! Lets see how smart users really are