Libreria C + GD
Invece di disegnare solo dei vecchi cerchi, ho pensato che sarebbe stato divertente trovare qualcosa di rosso nella foto e tracciare un cerchio attorno a quello.
Ecco alcuni esempi dei risultati ottenuti con un paio di foto da Wikimedia Commons :
Ed ecco il codice. Spero che sia un po 'disordinato, ma non troppo difficile da seguire:
#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;
}
Nota: Markdown ha incasinato il mio link nei commenti, quindi ti faccio solo notare che il codice utilizza la segmentazione per identificare tutte le aree di rosso nell'immagine, quindi traccia un cerchio attorno al più grande di questi. Ad esempio, questa immagine :
produce il seguente output: