Círculos rojos a mano alzada

19

En http://meta.stackoverflow.com , tenemos algunos memes propios. Uno de ellos es Freehand Red Circles.

Ver esta publicación :

Entonces, el desafío es,

¿Puedes dibujar círculos rojos a mano alzada ... con código?

Restricciones adicionales:

  • Tomará una imagen como entrada, y debe generar la imagen con un círculo rojo a mano alzada agregado.
  • Debe ser predecible, es decir, la misma entrada de imagen debe dar como resultado la misma salida. Puede usar la aleatoriedad, pero los resultados deben ser consistentes para la misma entrada.
  • La salida debe ser exactamente la misma imagen que la entrada, excepto con un círculo (sin otras alteraciones).
  • El círculo rojo a mano alzada debe verse a mano alzada (¡no hay círculos perfectos!), Debe ser rojo (obviamente) y parecerse generalmente a un círculo (no a líneas onduladas al azar).

Este es un , por lo que la respuesta con más votos positivos a principios de marzo de 2014 ganará. No existe un objetivo específico, aparte de los "círculos rojos a mano alzada", ¡así que sea lo más creativo posible para obtener la mayor cantidad de votos! (Para ser lo más imparcial posible, votaré cualquier respuesta que siga las reglas).

Pomo de la puerta
fuente
11
Creo que esto necesita un poco más de aclaración. ¿Estamos para a) dibujar un círculo en un lienzo blanco liso, b) tomar una imagen que contenga texto y dibujar un círculo alrededor del bloque de texto, o c) tomar un texto y crear una imagen del texto con un rodearlo?
primo
3
+1 a @primo. Además, hay otras cosas a tener en cuenta: si todo lo que tenemos que hacer es dibujar un círculo, ¿es el mismo círculo cada vez o el programa debe ser capaz de dibujar círculos diferentes, y esos círculos son simplemente diferentes al azar, o de alguna manera especificado por la entrada del usuario? ¿El programa debe ser capaz de manejar la entrada del usuario para determinar el tamaño o la forma del círculo? ¿Importa en qué formato está la salida de la imagen, o alguien podría inventar un ingenioso arte ASCII?
Iszi
2
Creo que la respuesta es "este es un concurso de popularidad, así que impresiona a tus amigos del código de golf"
McKay
No sé lo que no está claro sobre esta pregunta. @Iszi: la palabra clave es a mano alzada. Abre Paint o GIMP y dibuja algunos círculos a mano alzada, ¿se ven todos iguales? Según la descripción y el enlace, parece que tienes que dibujar círculos alrededor de algo, lo que implicaría X e Y y tamaño. ¿Qué importa qué formato de archivo use? Simplemente ejecútelo a través de un convertidor si desea PNG, JPEG o lo que sea.
Yo creo con McKay. Si quieres muchos votos a favor, dibuja círculos aleatorios a mano alzada. De lo contrario, codifique su círculo.
Hosch250

Respuestas:

13

C - aproximadamente 750 720 bytes si se exprime *

Creo que se me ocurrió algo que parece bastante libre.

  • comienza en un ángulo aleatorio
  • dibuja un círculo completo más o menos un poco
  • usa una línea gruesa y ondulada (¡quizás demasiado ondulada!)
  • es personalizable cambiando un MAGICnúmero

Compilar:

gcc -o freehand freehand.c -lm

Correr:

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

Ejemplo:

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

Antes de:

antes de

Después:

Después

Código:

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

* y usando Upara UNIFORMy MparaMAGIC


fuente
25

Biblioteca C + GD

En lugar de dibujar círculos en cualquier lugar antiguo, pensé que sería divertido encontrar algo rojo en la imagen y dibujar un círculo alrededor de eso.

Estos son algunos ejemplos de los resultados obtenidos con unas cuantas fotos de Wikimedia Commons :

cosas rojas con círculos que aparecen a su alrededor

Y aquí está el código. Es un poco desordenado, pero no demasiado difícil de seguir, espero:

#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 desordenó mi enlace en los comentarios, así que solo señalaré que el código usa la segmentación para identificar todas las áreas de rojo en la imagen, y luego dibuja un círculo alrededor de la más grande. Por ejemplo, esta imagen :

cubo rojo y pala en una playa

produce el siguiente resultado:

el cubo rojo tiene un círculo alrededor, porque es más grande que la pala

ossifrage aprensivo
fuente
1
¡Buen trabajo! ;) Va más con el tema de dibujarlos para enfatizar algo. Pero tengo curiosidad por saber qué haría si hubiera dos objetos rojos ... (+1)
Pomo de la puerta
2
Convierte todas las áreas rojas en diferentes segmentos y elige la más grande. Entonces, por ejemplo, en esta foto de un cubo rojo y una pala , el cubo gana. Aquí está el resultado
ossifrage aprensivo
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 toma los siguientes parámetros:

  • imagen: la imagen que se marcará con un círculo
  • rad: el radio del círculo, en fracción del ancho de la imagen
  • xPos: la posición del centro del círculo a lo largo de x, de 0 a 1 (predeterminado = .5)
  • yPos: la posición del centro del círculo a lo largo de y, de 0 a 1 (predeterminado = .5)
  • color: color de tinta (predeterminado = rojo oscuro)
  • espesor: grosor del trazo (predeterminado = .01)
  • ejes: si se muestran los ejes (predeterminado = Falso)

Ejemplos

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

pic1

Un radio diferente, ubicación, color azul, trazo más grueso, mostrando ejes.

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

pic2

DavidC
fuente
¡Wow muy agradable! ¿Es esto al azar, sin embargo? (Debe producir la misma salida para la misma entrada.)
Pomo de la puerta
Usé aleatoriedad para las desviaciones de un círculo verdadero. Pensé que estaba bien. Si no, puedo cablear la forma.
DavidC
"Debe ser predecible, es decir, la misma entrada de imagen debe dar como resultado la misma salida. Puede usar la aleatoriedad, pero los resultados deben ser consistentes para la misma entrada". Debe haber alguna forma de obtener un RNG sembrado en Mathematica, ¿verdad?
Pomo de la puerta
Sí, SeedRandomparece hacer el truco.
DavidC
Muy bien, genial! +1
Pomo de la puerta