Cercles rouges à main levée

19

Sur http://meta.stackoverflow.com , nous avons quelques mèmes à nous. L'un d'eux est Freehand Red Circles.

Voir cet article :

Donc, le défi est,

pouvez-vous dessiner des cercles rouges à main levée ... avec du code?

Restrictions supplémentaires:

  • Vous prendrez une image en entrée et vous devrez la sortir avec un cercle rouge à main levée ajouté.
  • Doit être prévisible, c'est-à-dire que la même entrée d'image doit donner la même sortie. Vous pouvez utiliser l'aléatoire, mais les résultats doivent être cohérents pour la même entrée.
  • La sortie doit être exactement la même image que l'entrée, sauf avec un cercle (pas d'autres modifications).
  • Le cercle rouge à main levée doit ressembler à main levée (pas de cercles parfaits!), Être rouge (évidemment) et ressembler généralement à un cercle (pas de lignes ondulées aléatoires).

Il s'agit d'un , donc la réponse avec le plus de votes au début de mars 2014 sera gagnante. Il n'y a pas d'objectif spécifique, à part les "cercles rouges à main levée", alors soyez aussi créatif que possible pour obtenir le plus de votes positifs! (Pour être aussi impartial que possible, je vais voter pour toute réponse qui respecte les règles.)

Poignée de porte
la source
11
Je pense que cela nécessite un peu plus de clarification. Sommes-nous à a) dessiner un rien mais un cercle sur une toile blanche, b) prendre une image contenant du texte, et dessiner un cercle autour du bloc de texte, ou c) prendre un texte, et créer une image du texte avec un tourner autour?
primo
3
+1 à @primo. En outre, il y a d'autres choses à considérer: si tout ce que nous devons faire est de dessiner un cercle, est-ce le même cercle à chaque fois ou le programme doit-il être capable de dessiner des cercles différents - et ces cercles doivent-ils être différents au hasard, ou en quelque sorte spécifié par l'entrée de l'utilisateur? Le programme doit-il être capable de gérer les entrées des utilisateurs pour déterminer la taille ou la forme du cercle? Le format de la sortie d'image est-il important, ou quelqu'un pourrait-il simplement trouver un art ASCII intelligent?
Iszi
2
Je pense que la réponse est "c'est un concours de popularité, alors impressionnez vos amis de code-golf"
McKay
Je ne sais pas ce qui n'est pas clair sur cette question. @Iszi - Le mot clé est à main levée. Ouvrez Paint ou GIMP et dessinez des cercles à main levée, ont-ils tous la même apparence? D'après la description et le lien, il semble que vous devez dessiner des cercles autour de quelque chose, ce qui impliquerait X & Y et la taille. Quel est le format de fichier que vous utilisez? Exécutez-le simplement via un convertisseur si vous voulez PNG, JPEG ou autre.
Je crois avec McKay. Si vous voulez beaucoup de votes positifs, dessinez des cercles à main levée aléatoires. Sinon, codez en dur votre cercle.
Hosch250

Réponses:

13

C - environ 750 720 octets si pressé *

Je pense que j'ai trouvé quelque chose qui semble assez libre.

  • commence à un angle aléatoire
  • dessine un cercle complet plus ou moins un peu
  • utilise une ligne épaisse et ondulée (peut-être trop ondulée!)
  • est personnalisable en changeant un MAGICnombre

Compiler:

gcc -o freehand freehand.c -lm

Courir:

./freehand [X center in % W] [Y center in % H] [radius in % diagonal] < [PPM file input] > [PPM file output]

Exemple:

./freehand 28.2 74.5 3.5 < screenshot.ppm > freehand.ppm

Avant:

Avant

Après:

Après

Code:

#include <stdlib.h>
#include <stdio.h>
#include <math.h>

#define MAGIC      42
#define UNIFORM(x) ((x) * (double)rand() / (double)RAND_MAX)

typedef struct {unsigned char r, g, b;} RGB;

int main(int argc, char **argv)
{
    int W, H, i, f, g, x, y;
    double X, Y, R, a, r;
    RGB *p;

    srand(MAGIC);

    if (argc != 4 || scanf("P6 %d %d 255\n", &W, &H) != 2)
        return 1;

    p = malloc(sizeof(RGB) * W * H);

    fread(p, sizeof(RGB), W * H, stdin);

    X = W * atof(argv[1]) / 100.0;
    Y = H * atof(argv[2]) / 100.0;
    R = hypot(W, H) * atof(argv[3]) / 100.0;

    for (a = UNIFORM(M_PI), i = 2.0 * M_PI * R + UNIFORM(R / 4.0), r = R; i > 0; i--, a += 1.0 / R)
    {
        r += UNIFORM(2.0) - 1.0;
        f = sin(a) * r + X;
        g = cos(a) * r + Y;

        for (x = f - 2; x <= f + 2; x++)
        {
            for (y = g - 2; y <= g + 2; y++)
            {
                if (x >= 0 && x < W && y >= 0 && y < H)
                {
                    RGB *s = p + y * W + x;
                    s->r = 255;
                    s->g = 0;
                    s->b = 0;
                }
            }
        }
    }

    printf("P6 %d %d 255\n", W, H);
    fwrite(p, sizeof(RGB), W * H, stdout);

    free(p);

    return 0;
}

* et en utilisant Upour UNIFORMet MpourMAGIC


la source
25

Bibliothèque C + GD

Au lieu de simplement dessiner des cercles n'importe où, j'ai pensé qu'il serait amusant de trouver quelque chose de rouge dans l'image et de dessiner un cercle autour de cela.

Voici quelques exemples des résultats obtenus avec un peu de photos de Wikimedia Commons :

des choses rouges avec des cercles apparaissant autour d'eux

Et voici le code. C'est un peu brouillon, mais pas trop difficile à suivre, j'espère:

#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;
}

Remarque: Markdown a gâché mon lien dans les commentaires, je vais donc souligner que le code utilise la segmentation pour identifier toutes les zones de rouge dans l'image, puis dessine un cercle autour de la plus grande d'entre elles. Par exemple, cette image :

seau rouge et bêche sur une plage

produit la sortie suivante:

le seau rouge a un cercle autour, car il est plus grand que la bêche

ossifrage délicat
la source
1
Bon travail! ;) Va plus avec le thème de les dessiner pour souligner quelque chose. Mais je suis curieux de savoir ce que ça ferait s'il y avait deux objets rouges ...? (+1)
Poignée de porte
2
Il convertit toutes les zones rouges en différents segments et choisit le plus grand. Ainsi, par exemple, sur cette photo d'un seau rouge et d'une pelle , le seau gagne. Voici le résultat
squeamish ossifrage
10

Mathematica

ClearAll[f]
f[image_,rad_, xPos_:.5,yPos_:.5,color_:Darker[Red,0.3],thick_:.01,axes_:False]:=
 Module[{i=ImageDimensions[image],rr,y=SeedRandom[2]},
 rr:=RandomReal[{-.1,.1}];
 Show[image,Graphics[{color,JoinForm["Round"],CapForm["Round"],Thickness[thick],
 Line[t=Table[{rad i[[2]] (Cos[z]+rr)+i[[1]]xPos,rad i[[2]] (Sin[z]+rr)+i[[2]] yPos},
 {z,0, 2 Pi+2Pi/12,Pi/12}]]}],Axes-> axes]]

f prend les paramètres suivants:

  • image: l'image qui sera marquée d'un cercle
  • rad: le rayon du cercle, en fraction de la largeur de l'image
  • xPos: la position du centre du cercle le long de x, de 0 à 1 (par défaut = 0,5)
  • yPos: la position du centre du cercle le long de y, de 0 à 1 (par défaut = 0,5)
  • couleur: couleur d'encre (par défaut = rouge foncé)
  • épaisseur: épaisseur du trait (par défaut = .01)
  • axes: afficher les axes (par défaut = False)

Exemples

text = Import["text.png"]
f[text,.13,.58,.23]

pic1

Un rayon différent, un emplacement, une couleur bleue, un trait plus épais, l'affichage des axes.

f[text,.22,.7,.5,Blue,.015,True]

pic2

DavidC
la source
Wow très agréable! Mais est-ce aléatoire? (Il doit produire la même sortie pour la même entrée.)
Poignée de porte
J'ai utilisé le hasard pour les écarts par rapport à un vrai cercle. Je pensais que ça allait. Sinon, je peux câbler la forme.
DavidC
"Doit être prévisible, c'est-à-dire que la même entrée d'image doit entraîner la même sortie. Vous pouvez utiliser l'aléatoire, mais les résultats doivent être cohérents pour la même entrée." Il doit y avoir un moyen d'obtenir un RNG prédéfini dans Mathematica, non?
Poignée de porte
Oui, SeedRandomsemble faire l'affaire.
DavidC
D'accord, super! +1
Poignée de porte