C + GD library
Instead of just drawing circles any old where, I thought it would be fun to find something red in the picture and draw a circle around that.
Here are some examples of the results obtained with a few photos from Wikimedia Commons:
And here's the code. It's a bit messy, but not too difficult to follow, I hope:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <gd.h>
#define min(a,b) ((a)<(b)?(a):(b))
#define max(a,b) ((a)>(b)?(a):(b))
/* Used for image segmentation */
int floodfill(int *tmp, int i, int w, int id) {
int np=1;
tmp[i]=id;
if (tmp[i-w-1]<0) np+=floodfill(tmp,i-w-1,w,id);
if (tmp[i-w]<0) np+=floodfill(tmp,i-w,w,id);
if (tmp[i-w+1]<0) np+=floodfill(tmp,i-w+1,w,id);
if (tmp[i-1]<0) np+=floodfill(tmp,i-1,w,id);
if (tmp[i+1]<0) np+=floodfill(tmp,i+1,w,id);
if (tmp[i+w-1]<0) np+=floodfill(tmp,i+w-1,w,id);
if (tmp[i+w]<0) np+=floodfill(tmp,i+w,w,id);
if (tmp[i+w+1]<0) np+=floodfill(tmp,i+w+1,w,id);
return np;
}
int main(int argv, char *argc[]) {
FILE *infile,*outfile;
gdImagePtr img;
int *t, *tmp;
int w,h,x,y,r,g,b;
int c,redness,rgb;
int i,np,max,min,thresh;
int xt,yt,n;
int areaID,size,maxID;
double xmin,ymin,xmax,ymax,rad,r0,th;
gdPoint v[33];
/* Check command line and open source JPEG file */
if (argv!=3) return printf("Usage: %s <in.jpg> <out.jpg>\n",argc[0]);
if (!(infile=fopen(argc[1],"r"))) return printf("Can't open <%s>\n",argc[1]);
if (!(img=gdImageCreateFromJpeg(infile))) return printf("Bad JPEG: <%s>\n",argc[1]);
fclose(infile);
/* Extract red pixels and auto-threshold */
w=img->sx;
h=img->sy;
np=w*h;
t=tmp=calloc(np,sizeof(int));
for (max=0,min=255,y=1;y<h-1;y++) {
for (x=1;x<w-1;x++) {
rgb=gdImageGetTrueColorPixel(img,x,y);
r = (rgb&0xff0000)>>16;
g = (rgb&0xff00)>>8;
b = rgb&0xff;
redness = max(0,r-(max(g,b)+abs(g-b)));
if (redness>max) max=redness;
if (redness<min) min=redness;
*t++ = redness;
}
t += 2;
}
thresh = (max+min)/2;
for (t=tmp,i=0;i<np;i++,t++) *t=((*t>thresh)?-1:0);
/* Label each area detected */
areaID=1;
maxID=0;
max=-1;
for (t=tmp,i=0;i<np;i++,t++) {
if (*t<0) {
size=floodfill(tmp,i,w,areaID);
if (size>max) {
max = size;
maxID = areaID;
}
areaID++;
}
}
/* Calculate centre coordinates and area */
if (max>0) {
xt=yt=n=xmax=ymax=0;
xmin=w; ymin=h;
for (t=tmp,y=0;y<h;y++) {
for (x=0;x<w;x++) {
if (*t++==maxID) {
xt+=x;
yt+=y;
n++;
if (x<xmin) xmin=x;
if (y<ymin) ymin=y;
if (x>xmax) xmax=x;
if (y>ymax) ymax=y;
}
}
}
x = xt/(2*n) + (xmax+xmin)/4;
y = yt/(2*n) + (ymax+ymin)/4;
r0 = max(20,min(min(w,h),max(xmax-xmin,ymax-ymin))/2);
}
/* Default circle if nothing found */
else {
x=w/2; y=h/2; r0=min(w,h)/3;
}
/* Draw a red circle */
for (th=4.0,i=0;i<33;i++) {
rad = r0 * (1.2 + (" ,<MYZVSB>@EJIOSWZfgb^bbfgeZTOI@2"[i]-87)/160.0);
v[i].x = x + rad * sin(th);
v[i].y = y + rad * cos(th);
th += 0.22;
}
gdImageSetThickness(img,7);
c = gdImageColorAllocate(img,255,0,0);
gdImageOpenPolygon(img,v,33,c);
/* Output results to file */
printf("Saving...\n");
if (!(outfile=fopen(argc[2],"w"))) {
return printf("Can't open <%s> for writing\n",argc[2]);
}
gdImageJpeg(img,outfile,85);
fclose(outfile);
gdImageDestroy(img);
printf("Finished\n");
return 0;
}
Note: Markdown messed up my link in the comments, so I'll just point out that the code uses segmentation to identify all the areas of red in the picture, and then draws a circle around the largest of these. For example, this image:
produces the following output:
11I think this needs a bit more clarification. Are we to a) draw a nothing but a circle on a plain white canvas, b) take an image containing text, and draw a circle around the text block, or c) take a text, and create an image of the text with a circle around it? – primo – 2014-01-29T14:19:52.923
3+1 to @primo. Also, there's other things to be considered: If all we need to do is draw a circle, is it the same circle every time or does the program need to be capable of drawing different circles - and are those circles to just be randomly different, or somehow specified by user input? Does the program need to be capable of handling user input at all, to determine the size or shape of the circle? Does it matter what format the image output is in, or could someone just come up with some clever ASCII art? – Iszi – 2014-01-29T15:53:19.203
2I think the answer is "this is a popularity contest, so impress your code-golf buddies" – McKay – 2014-01-29T16:39:36.697
I don't know what is unclear about this question. @Iszi - The key word is freehand. Open up Paint or GIMP and draw some freehand circles, do they all look the same? From the description and the link, it looks like you have to draw circles around something, which would imply X & Y and size. What does it matter what file format you use? Just run it through a converter if you want PNG, JPEG or whatever. – None – 2014-01-29T17:13:34.173
I believe with McKay. If you want a lot of upvotes, draw random freehand circles. Otherwise, hardcode your circle in. – None – 2014-01-29T19:33:38.590
@primo Any of them; it's your decision. – Doorknob – 2014-01-29T20:40:45.073
@primo Okay, I've updated the question to make it have a more concrete goal. – Doorknob – 2014-01-30T00:43:49.610
@Iszi (see above comments) – Doorknob – 2014-01-30T00:44:25.567