Círculos vermelhos à mão livre

19

Em http://meta.stackoverflow.com , temos alguns memes próprios. Um deles são os círculos vermelhos à mão livre.

Veja este post :

Então, o desafio é,

você pode desenhar círculos vermelhos à mão livre ... com código?

Restrições adicionais:

  • Você capturará uma imagem como entrada e deverá produzi-la com o círculo vermelho à mão livre adicionado.
  • Deve ser previsível, ou seja, a mesma entrada de imagem deve resultar na mesma saída. Você pode usar a aleatoriedade, mas os resultados devem ser consistentes para a mesma entrada.
  • A saída deve ser exatamente a mesma imagem que a entrada, exceto com círculo (sem outras alterações).
  • O círculo vermelho à mão livre deve parecer à mão livre (sem círculos perfeitos!), Ser vermelho (obviamente) e parecer geralmente com um círculo (sem linhas onduladas aleatórias).

Como é um , a resposta com mais votos positivos no início de março de 2014 será vitoriosa. Não há um objetivo específico, além de "círculos vermelhos à mão livre", portanto seja o mais criativo possível para obter o máximo de votos! (Para ser o mais imparcial possível, votarei em qualquer resposta que siga as regras.)

Maçaneta da porta
fonte
11
Eu acho que isso precisa de um pouco mais de esclarecimento. Devemos: a) desenhar apenas um círculo em uma tela branca lisa, b) tirar uma imagem contendo texto e desenhar um círculo em torno do bloco de texto ou c) pegar um texto e criar uma imagem do texto com um circule em torno dele?
Primo
3
+1 para @primo. Além disso, há outras coisas a serem consideradas: se tudo o que precisamos fazer é desenhar um círculo, é sempre o mesmo círculo ou o programa precisa ser capaz de desenhar círculos diferentes - e esses círculos são aleatoriamente diferentes, ou de alguma forma especificado pela entrada do usuário? O programa precisa ser capaz de lidar com a entrada do usuário, para determinar o tamanho ou a forma do círculo? Importa em que formato está a saída da imagem ou alguém poderia apresentar alguma arte ASCII inteligente?
Iszi
2
Acho que a resposta é "este é um concurso de popularidade, assim impressionar seus amigos code-golfe"
McKay
Não sei o que não está claro sobre esta questão. @Iszi - A palavra-chave é à mão livre. Abra o Paint ou o GIMP e desenhe alguns círculos à mão livre, todos têm a mesma aparência? A partir da descrição e do link, parece que você precisa desenhar círculos em torno de algo, o que implicaria X & Y e tamanho. O que importa qual formato de arquivo você usa? Basta executá-lo através de um conversor, se você quiser PNG, JPEG ou qualquer outra coisa.
Eu acredito com McKay. Se você deseja muitas votações, desenhe círculos à mão livre aleatórios. Caso contrário, codificar seu círculo no.
Hosch250

Respostas:

13

C - cerca de 750 720 bytes se espremido *

Acho que criei algo que parece à mão livre o suficiente.

  • começa em um ângulo aleatório
  • desenha um círculo completo mais ou menos um pouco
  • usa uma linha rabiscada grossa (talvez muito rabiscada!)
  • é personalizável alterando um MAGICnúmero

Compilar:

gcc -o freehand freehand.c -lm

Corre:

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

Exemplo:

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

Antes:

Antes

Depois de:

Depois de

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

* e usando Upara UNIFORMe MparaMAGIC


fonte
25

Biblioteca C + GD

Em vez de apenas desenhar círculos onde quer que fosse, pensei que seria divertido encontrar algo vermelho na imagem e desenhar um círculo em torno disso.

Aqui estão alguns exemplos dos resultados obtidos com um algumas fotos de Wikimedia Commons :

coisas vermelhas com círculos aparecendo ao seu redor

E aqui está o código. É um pouco confuso, mas não muito 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: O Markdown atrapalhou o meu link nos comentários, então vou apenas salientar que o código usa a segmentação para identificar todas as áreas de vermelho na imagem e, em seguida, desenha um círculo ao redor da maior delas. Por exemplo, esta imagem :

balde vermelho e pá na praia

produz a seguinte saída:

o balde vermelho tem um círculo ao redor, porque é maior que a pá

ossifrage melindroso
fonte
11
Bom trabalho! ;) Vai mais com o tema de desenhá-los para enfatizar alguma coisa. Mas estou curioso sobre o que faria se houvesse dois objetos vermelhos ...? (+1)
Maçaneta da porta
2
Ele converte todas as áreas vermelhas em diferentes segmentos e escolhe a maior. Por exemplo, nesta foto de um balde e pá vermelhos , o balde vence. Aqui está o resultado
ossifrage melindroso
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 usa os seguintes parâmetros:

  • image: a imagem que será marcada com um círculo
  • rad: o raio do círculo, em fração da largura da imagem
  • xPos: a posição do centro do círculo ao longo de x, de 0 a 1 (padrão = 0,5)
  • yPos: a posição do centro do círculo ao longo de y, de 0 a 1 (padrão = 0,5)
  • cor: cor da tinta (padrão = vermelho escuro)
  • espessura: espessura do traçado (padrão = 0,01)
  • eixos: se os eixos devem ser exibidos (padrão = Falso)

Exemplos

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

pic1

Um raio diferente, localização, cor azul, curso mais espesso, exibição de eixos.

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

pic2

DavidC
fonte
Wow muito legal! Isso é aleatório? (Ele deve produzir a mesma saída para a mesma entrada.)
Maçaneta da porta
Eu usei aleatoriedade para os desvios de um círculo verdadeiro. Eu pensei que estava tudo bem. Caso contrário, eu posso conectar a forma.
DavidC
"Deve ser previsível, ou seja, a mesma entrada de imagem deve resultar na mesma saída. Você pode usar a aleatoriedade, mas os resultados devem ser consistentes para a mesma entrada". Deve haver alguma maneira de obter um RNG semeado no Mathematica, certo?
Maçaneta
Sim, SeedRandomparece fazer o truque.
DavidC
Tudo bem, ótimo! +1
Maçaneta da porta