Freihändig rote Kreise

19

Drüben auf http://meta.stackoverflow.com haben wir einige eigene Memes. Einer von ihnen ist Freehand Red Circles.

Siehe diesen Beitrag :

Die Herausforderung ist also,

Kannst du freihändig rote Kreise zeichnen ... mit Code?

Zusätzliche Einschränkungen:

  • Sie nehmen ein Bild als Eingabe und müssen es mit einem freihändigen roten Kreis ausgeben.
  • Muss vorhersehbar sein, dh gleiche Bildeingabe muss zu gleicher Ausgabe führen. Sie können die Zufälligkeit verwenden, die Ergebnisse müssen jedoch für dieselbe Eingabe konsistent sein.
  • Die Ausgabe muss genau das gleiche Bild wie die Eingabe sein, außer mit Kreis (keine anderen Änderungen).
  • Der freihändige rote Kreis muss freihändig aussehen (keine perfekten Kreise!), Rot sein (offensichtlich) und im Allgemeinen wie ein Kreis aussehen (keine zufälligen verzerrten Linien).

Dies ist ein , daher wird die Antwort mit den meisten positiven Stimmen Anfang März 2014 gewinnen. Es gibt kein bestimmtes Ziel, außer "freihändige rote Kreise". Sei also so kreativ wie möglich, damit du die meisten positiven Stimmen bekommst! (Um so unvoreingenommen wie möglich zu sein, werde ich jede Antwort, die den Regeln folgt, positiv bewerten.)

Türknauf
quelle
11
Ich denke, das bedarf einer etwas genaueren Klärung. Sollen wir a) nichts als einen Kreis auf eine einfache weiße Leinwand zeichnen, b) ein Bild mit Text aufnehmen und einen Kreis um den Textblock ziehen, oder c) einen Text aufnehmen und ein Bild des Textes mit a erstellen? umkreise es?
Primo
3
+1 an @primo. Darüber hinaus gilt es noch Folgendes zu beachten: Wenn wir nur einen Kreis zeichnen müssen, muss dieser jedes Mal derselbe Kreis sein, oder muss das Programm in der Lage sein, verschiedene Kreise zu zeichnen - und diese Kreise dürfen nur zufällig unterschiedlich sein. oder irgendwie durch Benutzereingaben angegeben? Muss das Programm überhaupt in der Lage sein, Benutzereingaben zu verarbeiten, um die Größe oder Form des Kreises zu bestimmen? Ist es wichtig, in welchem ​​Format die Bildausgabe erfolgt, oder kann sich jemand eine clevere ASCII-Grafik einfallen lassen?
Iszi
2
Ich denke, die Antwort lautet "Dies ist ein Beliebtheitswettbewerb, also beeindrucken Sie Ihre Code-Golf-Freunde"
McKay
Ich weiß nicht, was über diese Frage unklar ist. @Iszi - Das Schlüsselwort ist freihändig. Öffne Paint oder GIMP und zeichne ein paar Freihandkreise, sehen sie alle gleich aus? Aus der Beschreibung und dem Link geht hervor, dass Sie Kreise um etwas zeichnen müssen, was X & Y und Größe implizieren würde. Was macht es aus, welches Dateiformat Sie verwenden? Führen Sie es einfach durch einen Konverter, wenn Sie PNG, JPEG oder was auch immer wollen.
Ich glaube mit McKay. Wenn Sie viele positive Stimmen wünschen, zeichnen Sie zufällige Freihandkreise. Andernfalls codieren Sie Ihren Kreis fest ein.
Hosch250

Antworten:

13

C - ungefähr 750 720 Bytes, wenn sie zusammengedrückt werden *

Ich denke, ich habe etwas gefunden, das freihändig genug aussieht.

  • beginnt in einem zufälligen Winkel
  • zeichnet einen vollen Kreis plus oder minus ein bisschen
  • verwendet eine dicke schnörkelige Linie (vielleicht zu schnörkelig!)
  • ist durch Ändern einer MAGICZahl anpassbar

Kompilieren:

gcc -o freehand freehand.c -lm

Lauf:

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

Beispiel:

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

Vor:

Vor

Nach:

Nach

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

* und mit Ufür UNIFORMund MfürMAGIC


quelle
25

C + GD Bibliothek

Anstatt nur Kreise zu zeichnen, dachte ich, es würde Spaß machen, etwas Rotes auf dem Bild zu finden und einen Kreis darum zu zeichnen.

Hier sind einige Beispiele der Ergebnisse, die mit ein paar Fotos von Wikimedia Commons erzielt wurden :

rote Dinge mit Kreisen um sie herum

Und hier ist der Code. Es ist ein bisschen chaotisch, aber nicht zu schwer zu folgen, hoffe ich:

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

Hinweis: Markdown hat meinen Link in den Kommentaren durcheinander gebracht, daher möchte ich nur darauf hinweisen, dass der Code die Segmentierung verwendet , um alle roten Bereiche im Bild zu identifizieren , und dann einen Kreis um die größten davon zeichnet. Zum Beispiel dieses Bild :

roten Eimer und Spaten am Strand

erzeugt die folgende Ausgabe:

Der rote Eimer ist von einem Kreis umgeben, da er größer als der Spaten ist

zimperliches Ossifrage
quelle
1
Gute Arbeit! ;) Geht eher mit dem Thema Zeichnen um sie etwas hervorzuheben. Aber ich bin gespannt, was es tun würde, wenn es zwei rote Objekte gäbe ...? (+1)
Türknauf
2
Es wandelt alle roten Bereiche in verschiedene Segmente um und wählt das größte aus. So gewinnt zum Beispiel in diesem Foto von einem roten Eimer und einem Spaten der Eimer. Hier ist das Ergebnis
zimperliche 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 nimmt die folgenden Parameter an:

  • Bild: Das Bild, das mit einem Kreis markiert wird
  • rad: Der Radius des Kreises in Bruchteilen der Bildbreite
  • xPos: Die Position des Mittelpunkts des Kreises entlang x von 0 bis 1 (Standard = 0,5)
  • yPos: Die Position des Mittelpunkts des Kreises entlang y von 0 bis 1 (Standard = 0,5)
  • Farbe: Tintenfarbe (Standard = dunkelrot)
  • Dicke: Strichstärke (Standard = 0,01)
  • Achsen: ob Achsen angezeigt werden sollen (Standard = Falsch)

Beispiele

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

pic1

Ein anderer Radius, eine andere Position, eine andere blaue Farbe, ein dickerer Strich und Anzeigen von Achsen.

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

pic2

DavidC
quelle
Wow, sehr nett! Ist das aber zufällig? (Es muss dieselbe Ausgabe für dieselbe Eingabe erzeugen.)
Türknauf
Ich habe Zufälligkeit für die Abweichungen von einem wahren Kreis verwendet. Ich fand das ok. Wenn nicht, kann ich die Form fest verdrahten.
DavidC
"Muss vorhersehbar sein, dh die gleiche Bildeingabe muss zu der gleichen Ausgabe führen. Sie können die Zufälligkeit verwenden, aber die Ergebnisse müssen für die gleiche Eingabe konsistent sein." In Mathematica muss es eine Möglichkeit geben, ein gesätes RNG zu bekommen, oder?
Türknauf
Ja, SeedRandomscheint den Trick zu tun.
DavidC
Okay, großartig! +1
Türklinke