Overlapping Circles

This is a way of creating a kind of impressionistic version of an image. The image is "painted" with circles of color given by the average color of the pixels in the area of the image that the circle covers.

The way this works is that a random center is determined at a point that is pure black in the painted image (i.e., it has not been painted yet). The radius of the circle starts small and increases until the colors of the pixels in the circle show too much variation. Then that radius is used and the circle is "painted".

This process is repeated indefinitely, but will eventually end when all pixels have been painted. The code below is sped up by using sampling to determine an estimate of the color variation inside each disk. Instead of checking all of the pixels, only a certain rather small percentage are checked. Changing this percentage has little affect on the resulting image, but can drastically influence the speed of the process.

The right image is the result of processing the left image with the code below.

rem
rem This is an example of image manipulation software written in Basic
rem using the freeware Macintosh METAL basic interpreter.
rem 
rem This program produces an interpretation of a given image
rem by randomly choosing centers for filled circles of color.
rem The radius of the circle is determined by checking to see 
rem that the colors of the pixels in the area of the circle in the
rem original picture are similar enough.  The radius is increased 
rem until the variation of the colors of the pixels exceeds a threshold
rem (specified by the variable thresh).  Then the color of the circle
rem is the average of the colors of the pixels in that circular area.
rem
rem Metal seems to have a problem with very large images, so try this on
rem relatively small ones, say 600 x 500 or smaller.
rem
rem Matthew M. Conroy, 2001.  
rem Do whatever you want to with this code, especially improve it.
rem

file$ = open preview dialog$
get quicktime pict size file$,picW,picH

resize console 20,50,picW+20,picH+50
 load quicktime pict file$

virtu = init screen (0,0,picW+0,picH+0)
set screen to virtu
cls
copyrect 0,0,picW,picH,0,0,picW,picH,0,0,virtu

set screen to console
cls

chkPixelsFact=0.1
thresh=1900

dim x(numCirc),y(numCirc),r(numCirc)
dim red(200),green(200),blue(200)

for i=1 to numCirc
x(i)=0
y(i)=0
r(i)=0
next i

endLessLoop:

set screen to console

loopUntilBlack:
x = int(rnd*(picW-1))
y = int(rnd*(picH-1))
get pixel x,y,red,green,blue
if ((red+green+blue)>0) then goto loopUntilBlack

rad=2 rem set the initial radius

set screen to virtu

radiusIncreaseLoop: rem yes, this is endless, but feel free to improve this code

rem increase the radius until the sample of pixels in the circle
rem show too much color variation

chkPixels  = int(1+chkPixelsFact*3.1415926535*rad*rad)
sumred=0: sumgreen=0: sumblue=0
sumred2 = 0: sumgreen2 = 0: sumblue2 = 0
for pix=1 to chkPixels rem look at the colors of chkPixels randomly chosen pixels
   radpix = rnd*rad
   thetapix = 360*rad
   xpix = abs(x + radpix*cos(thetapix))
   ypix = abs(y + radpix*sin(thetapix))
   if xpix> picW then xpix=picW-(xpix-picW)
   if ypix>picH  then ypix=picH-(ypix-picH)
   get pixel xpix,ypix,red,green,blue
   sumred=sumred+red
   sumgreen=sumgreen+green
   sumblue=sumblue+blue
   sumred2 = sumred2+red*red
   sumgreen2 = sumgreen2 + green*green
   sumblue2 = sumblue2 + blue*blue
next pix

meanred = sumred/chkPixels
meangreen = sumgreen/chkPixels
meanblue = sumblue/chkPixels

rem determine the standard deviation of the red, green, and blue values of the
rem chkPixels randomly chosen pixels

stdred = sqr( (sumred2-2*meanred*sumred + chkPixels*meanred*meanred)/chkPixels)
stdblue = sqr( (sumblue2-2*meanblue*sumblue + chkPixels*meanblue*meanblue)/chkPixels)
stdgreen = sqr( (sumgreen2-2*meangreen*sumgreen + chkPixels*meangreen*meangreen)/chkPixels)

rem if the standard deviation is small enough, increase the radius and continue

if ((stdred < thresh) and (stdblue < thresh) and (stdgreen < thresh)) then 
   rad=rad+1
   goto radiusIncreaseLoop:
endif

rem else stop increasing the radius, and plot the circle
set screen to console
forecolor meanred,meangreen,meanblue
fcircle x,y,rad

goto endLessLoop:





back