Lingkaran merah freehand

19

Di http://meta.stackoverflow.com , kami memiliki beberapa meme kami sendiri. Salah satunya adalah Lingkaran Merah Freehand.

Lihat posting ini :

Jadi, tantangannya adalah,

dapatkah kamu menggambar lingkaran merah dengan tangan bebas ... dengan kode?

Pembatasan tambahan:

  • Anda akan mengambil gambar sebagai input, dan Anda harus menampilkan gambar dengan lingkaran merah bebas ditambahkan.
  • Harus dapat diprediksi, yaitu input gambar yang sama harus menghasilkan output yang sama. Anda dapat menggunakan keacakan, tetapi hasilnya harus konsisten untuk input yang sama.
  • Output harus persis sama dengan input, kecuali dengan lingkaran (tidak ada perubahan lain).
  • Lingkaran merah bebas harus terlihat bebas (tidak ada lingkaran sempurna!), Berwarna merah (jelas), dan umumnya terlihat seperti lingkaran (tidak ada garis berlekuk acak).

Ini adalah , jadi jawaban dengan suara terbanyak pada awal Maret 2014 akan menang. Tidak ada tujuan khusus, selain "lingkaran merah bebas," jadi sekreatif mungkin agar Anda mendapatkan hasil maksimal! (Agar tidak bias mungkin, saya akan menghapus setiap jawaban yang mengikuti aturan.)

Gagang pintu
sumber
11
Saya pikir ini perlu sedikit klarifikasi. Apakah kita ke a) menggambar apa pun kecuali lingkaran di atas kanvas putih polos, b) mengambil gambar yang berisi teks, dan menggambar lingkaran di sekitar blok teks, atau c) mengambil teks, dan membuat gambar teks dengan lingkaran di sekitarnya?
Primo
3
+1 ke @primo. Juga, ada hal-hal lain yang perlu dipertimbangkan: Jika semua yang perlu kita lakukan adalah menggambar lingkaran, apakah itu lingkaran yang sama setiap kali atau apakah program harus mampu menggambar lingkaran yang berbeda - dan apakah lingkaran itu hanya berbeda secara acak, atau entah bagaimana ditentukan oleh input pengguna? Apakah program harus mampu menangani input pengguna sama sekali, untuk menentukan ukuran atau bentuk lingkaran? Apa bedanya format output gambar, atau bisakah seseorang memunculkan seni ASCII yang pintar?
Iszi
2
Saya pikir jawabannya adalah "ini adalah kontes popularitas, jadi kesan teman-teman kode-golf Anda"
McKay
Saya tidak tahu apa yang tidak jelas tentang pertanyaan ini. @Iszi - Kata kuncinya adalah freehand. Buka Paint atau GIMP dan gambar beberapa lingkaran bebas, apakah semuanya terlihat sama? Dari uraian dan tautan, sepertinya Anda harus menggambar lingkaran di sekitar sesuatu, yang akan menyiratkan X & Y dan ukuran. Apa bedanya format file apa yang Anda gunakan? Jalankan saja melalui konverter jika Anda ingin PNG, JPEG atau apa pun.
Saya percaya dengan McKay. Jika Anda ingin banyak upvotes, gambarkan lingkaran tangan bebas acak. Jika tidak, buat hardcode lingkaran Anda.
Hosch250

Jawaban:

13

C - sekitar 750 720 byte jika diperas *

Saya pikir saya datang dengan sesuatu yang terlihat cukup tangan-y.

  • mulai dari sudut acak
  • menggambar lingkaran penuh plus atau minus sedikit
  • menggunakan garis berlekuk tebal (mungkin terlalu berlekuk!)
  • dapat disesuaikan dengan mengubah MAGICnomor

Menyusun:

gcc -o freehand freehand.c -lm

Lari:

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

Contoh:

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

Sebelum:

Sebelum

Setelah:

Setelah

Kode:

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

* dan menggunakan Uuntuk UNIFORMdan MuntukMAGIC


sumber
25

Pustaka C + GD

Daripada hanya menggambar lingkaran di mana saja, saya pikir akan menyenangkan untuk menemukan sesuatu yang berwarna merah di gambar dan menggambar lingkaran di sekitarnya.

Berikut adalah beberapa contoh dari hasil yang diperoleh dengan sebuah beberapa foto dari Wikimedia Commons :

benda merah dengan lingkaran muncul di sekitarnya

Dan ini kodenya. Agak berantakan, tapi tidak terlalu sulit untuk diikuti, saya harap:

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

Catatan: Penurunan harga mengacaukan tautan saya di komentar, jadi saya hanya akan menunjukkan bahwa kode menggunakan segmentasi untuk mengidentifikasi semua area merah dalam gambar, dan kemudian menggambar lingkaran di sekitar yang terbesar dari ini. Misalnya, gambar ini :

ember merah dan sekop di pantai

menghasilkan output berikut:

ember merah memiliki lingkaran di sekitarnya, karena lebih besar dari sekop

lubang keras melengking
sumber
1
Pekerjaan yang baik! ;) Lebih sesuai dengan tema menggambar mereka untuk menekankan sesuatu. Tapi saya ingin tahu tentang apa yang akan dilakukan jika ada dua benda merah ...? (+1)
Gagang Pintu
2
Ini mengubah semua area merah menjadi segmen yang berbeda dan memilih yang terbesar. Jadi misalnya di foto ini ember merah dan sekop , ember menang. Inilah hasilnya
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 mengambil parameter berikut:

  • image: gambar yang akan ditandai dengan lingkaran
  • rad: jari-jari lingkaran, di sebagian kecil dari lebar gambar
  • xPos: posisi tengah lingkaran sepanjang x, dari 0 hingga 1 (default = .5)
  • yPos: posisi pusat lingkaran di sepanjang y, dari 0 hingga 1 (default = .5)
  • warna: warna tinta (standar = merah tua)
  • ketebalan: tebal goresan (default = .01)
  • sumbu: apakah akan menampilkan sumbu (default = Salah)

Contohnya

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

pic1

Jari-jari yang berbeda, lokasi, warna biru, goresan yang lebih tebal, menampilkan sumbu.

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

pic2

DavidC
sumber
Wow sangat bagus! Apakah ini acak? (Ini harus menghasilkan output yang sama untuk input yang sama.)
Gagang Pintu
Saya menggunakan keacakan untuk penyimpangan dari lingkaran yang benar. Saya pikir itu baik-baik saja. Jika tidak, saya bisa memasang bentuk.
DavidC
"Harus dapat diprediksi, yaitu input gambar yang sama harus menghasilkan output yang sama. Anda dapat menggunakan keacakan, tetapi hasilnya harus konsisten untuk input yang sama." Pasti ada cara untuk mendapatkan RNG unggulan di Mathematica, kan?
Gagang Pintu
Ya, SeedRandomsepertinya melakukan trik.
DavidC
Baiklah bagus! +1
Gagang Pintu