Square, Circle, Triangle,… Gear?

69

Menggunakan Algodoo dan Paint, saya membuat enam gambar monokromatik 300 × 300 dengan empat bentuk yang nyaman:

Gambar 1 Gambar 2 Gambar 3 Gambar 4 Gambar 5 Gambar 6

Kelas gambar ini memiliki properti berikut:

  • Mereka selalu 300 × 300 piksel, monokromatik (hanya hitam dan putih), dan memiliki empat wilayah putih yang sesuai dengan kotak, lingkaran, segitiga, dan roda gigi.
  • Bentuknya tidak pernah tumpang tindih atau saling menyentuh, juga tidak menyentuh batas gambar atau keluar batas.
  • Bentuknya selalu memiliki ukuran yang sama, tetapi mereka dapat diputar dan diposisikan dengan cara apa pun.

(Bentuknya juga memiliki area yang sama, meskipun ketika diraster seperti ini jumlah pikselnya tidak mungkin sama persis.)

Tantangan

Tulis program atau fungsi sesingkat mungkin yang menggunakan nama file dari gambar seperti itu dan mengubah semua piksel putih ...

  • merah (255, 0, 0)jika mereka berada di alun-alun.
  • biru (0, 0, 255)jika mereka berada di lingkaran.
  • hijau (0, 255, 0)jika mereka berada di segitiga.
  • kuning (255, 255, 0)jika mereka berada di gigi.

misalnya

Gambar 1 berwarna

Detail

Program Anda harus bekerja secara efektif untuk semua gambar input yang mungkin. (Hanya 300 × 300 gambar monokromatik yang akan dimasukkan.) Keenam gambar yang saya berikan hanyalah contoh, Anda mungkin tidak dapat meng-hardcode outputnya ke dalam program Anda.

Anda tidak dapat menggunakan perpustakaan atau fungsi visi komputer, built-in atau eksternal. Intinya adalah melakukan ini menggunakan operasi level-pixel Anda sendiri. Anda dapat menggunakan pustaka gambar yang memungkinkan Anda membuka dan mengubah gambar (mis. PIL untuk Python).

Anda dapat menggunakan format file gambar lossless umum untuk input dan output selama Anda tetap pada skema warna.

Anda dapat mengambil nama file gambar sebagai argumen fungsi, dari stdin, atau dari baris perintah. Gambar output dapat disimpan ke file baru, file yang sama, atau hanya ditampilkan.

Mencetak gol

Kiriman dengan byte paling sedikit menang. Saya dapat menguji pengiriman dengan gambar tambahan untuk menentukan validitasnya.

Hobi Calvin
sumber
Bolehkah kita menganggap inputnya hitam & putih tanpa anti-aliasing? Jika tidak, dapatkah kita menghapus anti-aliasing dari input anti-alias?
John Dvorak
@ JanDvorak Ya. Maksud saya monokromatik hanya hitam dan putih, jadi tidak mungkin ada anti-aliasing.
Hobi Calvin
1
Bolehkah kita memerlukan format input spesifik lebih dari sekadar ekstensi file? Yaitu, saya ingin saya masukan ASCII PBM tanpa komentar di dalamnya.
John Dvorak
12
Jadi ... saya mencoba menyelesaikan ini, dan saya berakhir dengan gambar ini . Tidak begitu yakin bagaimana, tapi hei, itu terlihat mewah. : P
Doorknob
2
Saya tidak ingin memposting solusi saya karena itu ide yang sama dengan Ell tetapi lebih buruk. Tapi saya hanya ingin mengatakan ini adalah tantangan kecil yang menyenangkan untuk dilakukan :)
Chris Burt-Brown

Jawaban:

8

J - 246.224 185 byte

load'viewmat'
(viewmat~0,(255*4 3$_2|.#:3720)/:/:@(<([:}.(>./%+/%#)@:(+/&:*:@(-"1)+/%#)@(4$.$.@:=)&>)<"0@~.@,))@(~.@,i.])@(>./**@{.)@((0,(,-)#:>:i.3)&|.)^:_@(*i.@:$)@(0<readimg_jqtide_)

Ini menyenangkan!

Saya menggunakan kembali komponen yang terhubung yang saya gunakan untuk tantangan "Apakah saya di ruangan terbesar" , dan menggunakan rasio antara rata-rata dan jarak maksimum semua titik ke masing-masing pusat komponen. Saya setuju untuk ini, karena skala dan invarian rotasi, dan tampaknya cukup baik untuk membedakan antara bentuk yang diberikan. Pemeringkatan nilai ini dari rendah ke tinggi memberi saya lingkaran urutan, roda gigi, bujur sangkar, dan segitiga, yang digunakan untuk mengubah urutan colormap.

Menampilkan hasilnya menggunakan addon viewmap. Tidak ada kotak alat yang digunakan kecuali untuk pembacaan dan keluaran file.

Robustness tampaknya tidak menjadi persyaratan, ini lepas landas 18 byte. 2 lebih banyak ruang yang tidak perlu, diganti &.>dengan &>in ratiodan &.:by &:dcent untuk 2 byte lainnya.

Keuntungan besar dalam hal kependekan dan kinerja compmenggunakan alih-alih cut( ;.). Dengan cara ini, gambar direplikasi dan dipindahkan ke semua 8 arah alih-alih memindai dengan jendela 3x3.

The idFungsi adalah ridiculously kompleks untuk apa yang diperlukan untuk melakukan. Sekarang ia menetapkan id ke piksel dalam objek dengan mengalikan gambar dengan array angka unik, karenanya mengatur BG ke nol.

Kode sedikit lebih dijelaskan:

load'viewmat'                                 NB. display only
imnames =: < ;. _2 (0 : 0)
C6IKR.png
DLM3y.png
F1ZDM.png
Oa2O1.png
YZfc6.png
chJFi.png
)

images =: (0<readimg_jqtide_) each imnames    NB. read all images in boxed array

id =: *i.@:$                                  NB. NB. assign one number to each non-background (non-zero) pixel
comp =: (>./ * *@{.)@shift^:_@id              NB. 8 connected neighbor using shift
  shift =: (>,{,~<0 _1 1)&|.                  NB. generate the original, and 8 shifted versions (automatically padding and cropping).
result =: comp each images                    NB. Execute comp verb for each image
col =: (~.@, i. ])                            NB. Color: give each component and BG a separate color.

NB. BG in 0, 0 Get all max distance to center % mean distance to center ratios
ratio  =: (< ([:}.rat@:dcent@getInd &>)  <"0@~.@,)
  getInd =: 4 $. $.@:=                        NB. get indices for component y in array x
  dcent  =: +/&.:*:@(-"1) +/%#                NB. distence from center each point
  rat    =: >./ % +/%#                        NB. ratio from distances

cm=: (255*4 3$_2|.#:3720)                     NB. colormap (except black).
(viewmat~ 0,cm /: /:@ratio )@col each result  NB. for each image, show the result, permuting the colormap according to ratio's

NB. almostgolf this
P1 =: (>./**@{.)@((0,(,-)#:>:i.3)&|.)^:_@(*i.@:$)@(0<readimg_jqtide_) NB. reading till components
P2 =: (<([:}.(>./%+/%#)@:(+/&:*:@(-"1)+/%#)@(4$.$.@:=)&>)<"0@~.@,) NB. recognition: get fraction mean vs max distance to center per component, toss BG.     
P3 =: (viewmat~0,(255*4 3$_2|.#:3720)/:/:@P2)@(~.@,i.])@P1    NB. piece together : permute colormap, display components

NB. seriousgolf
load'viewmat'
f =:(viewmat~0,(255*4 3$_2|.#:3720)/:/:@(<([:}.(>./%+/%#)@:(+/&:*:@(-"1)+/%#)@(4$.$.@:=)&>)<"0@~.@,))@(~.@,i.])@((>./**@{.)@shift^:_)@(*i.@:$)@(0<readimg_jqtide_)
NB. example usage:
f&> imnames NB. do for all images

Yang ini agak panjang untuk menjelaskan secara rinci, tetapi akan dilakukan jika ada minat.

jpjacobs
sumber
Pixel kanan atas dijamin bg. Sesuai OP "Bentuk tidak pernah tumpang tindih atau saling menyentuh, juga tidak menyentuh batas gambar atau keluar batas."
Dr. belisarius
Terima kasih, itu sangat membantu. (Sebenarnya yang saya maksud adalah pixel kiri atas, yang pertama di ravel) Ini mencukur deteksi latar belakang (22 byte).
jpjacobs
Secara dramatis mengurangi panjang, dan meningkatkan kinerja :)
jpjacobs
29

Mathematica, 459 392 byte

f=(d=ImageData@Import@#/.{a_,_,_}:>a;(For[a={};b={#&@@d~Position~1},b!={},c=#&@@b;b=Rest@b;d[[##&@@c]]=0;a~AppendTo~c;If[Extract[d,c+#]==1,b=b⋃{c+#}]&/@{e={1,0},-e,e={0,1},-e}];m=1.Mean@a;m=#-m&/@a;n=Count[Partition[Norm/@SortBy[m,ArcTan@@#&],300,1,1],l_/;l[[150]]==Max@l];(d[[##&@@#]]=Round[n^.68])&/@a)&/@Range@4;Image[d/.n_Integer:>{{0,0,0},,{0,1,0},{1,0,0},,,,{1,1,0},{0,0,1}}[[n+1]]])&

Tidak Disatukan:

f = (
 d = ImageData@Import@# /. {a_, _, _} :> a;
 (
    For[a = {}; b = {# & @@ d~Position~1},
     b != {},
     c = # & @@ b;
     b = Rest@b;
     d[[## & @@ c]] = 0;
     a~AppendTo~c;
     If[Extract[d, c + #] == 1, 
        b = b ⋃ {c + #}] & /@ {e = {1, 0}, -e, e = {0, 1}, -e}
     ];
    m = 1. Mean@a; m = # - m & /@ a;
    n = 
     Count[Partition[Norm /@ SortBy[m, ArcTan @@ # &], 300, 1, 1], 
      l_ /; l[[150]] == Max@l];
    (d[[## & @@ #]] = Round[n^.68]) & /@ a
    ) & /@ Range@4;
 Image[d /. 
   n_Integer :> {{0, 0, 0}, , {0, 1, 0}, {1, 0, 0}, , , , {1, 1, 
       0}, {0, 0, 1}}[[n + 1]]]
) &

Saya bisa menghemat 6 byte lebih banyak dengan mengubahnya m=1.Mean@a;m=#-m&/@a;menjadi m=#-Mean@a&/@a;, tetapi itu secara signifikan meledakkan waktu eksekusi, yang menjengkelkan untuk pengujian. (Perhatikan, bahwa ini adalah dua optimisasi: mengeluarkan perhitungan Mean@aout of loop dan menggunakan tipe simbolik yang tepat alih-alih angka floating point. Menariknya, penggunaan tipe yang tepat jauh lebih signifikan daripada menghitung rata-rata dalam setiap iterasi.)

Jadi ini adalah pendekatan nomor tiga:

  • Mendeteksi area dengan banjir.
  • Temukan perkiraan pusat setiap area dengan rata-rata semua koordinat piksel.
  • Sekarang untuk semua piksel dalam bentuk, mari kita plot jarak dari sudut vs ke pusat itu:

    masukkan deskripsi gambar di sini

    Segitiga memiliki 3 maxima yang jelas, kuadrat 4, roda gigi 16, dan lingkaran memiliki ton, karena fluktuasi aliasing tentang jari-jari konstan.

  • Kami menemukan jumlah maxima dengan melihat irisan 300 piksel (dipesan dengan sudut), dan menghitung irisan di mana piksel pada posisi 150adalah maksimum.
  • Kemudian kita hanya mewarnai semua piksel tergantung pada jumlah puncak (lingkarannya lebih dari 16, dan biasanya menghasilkan sekitar 20 puncak, karena ukuran irisannya).

Sebagai catatan, jika saya menggunakan ide Ell, dan cukup mengurutkan wilayah berdasarkan jarak terbesar antara piksel dan pusat, saya bisa melakukan ini dalam 342 byte:

f=(d=ImageData@Import@#/.{a_,_,_}:>a;MapIndexed[(d[[##&@@#]]=#&@@#2)&,SortBy[(For[a={};b={#&@@d~Position~1},b!={},c=#&@@b;b=Rest@b;d[[##&@@c]]=0;a~AppendTo~c;If[Extract[d,c+#]==1,b=b⋃{c+#}]&/@{e={1,0},-e,e={0,1},-e}];a)&/@Range@4,(m=Mean@#;Max[1.Norm[#-m]&/@#])&],{2}];Image[d/.n_Integer:>{{0,0,0},{0,0,1},{1,1,0},{1,0,0},{0,1,0}}[[n+1]]])&

Tetapi saya tidak bermaksud untuk bersaing dengan itu, selama semua orang menggunakan algoritma asli mereka sendiri, alih-alih bermain dengan yang lain.

Martin Ender
sumber
Solusi paling menarik!
CSharpie
25

Jawa, 1204 1132 1087 1076

Hanya untuk membuktikan pada diri sendiri bahwa saya bisa melakukan ini.

Saya memasukkan impor tepat di sebelah fungsi deklarasi; ini harus berada di luar kelas agar ini berfungsi:

import java.awt.*;import java.awt.image.*;import java.io.*;import java.util.*;import javax.imageio.*;

BufferedImage i;Set<Point>Q;void p(String a)throws Exception{i=new BufferedImage(302,302,1);i.getGraphics().drawImage(ImageIO.read(new File(a)),1,1,null);Set<Set<Point>>S=new HashSet<>();for(int y=0;y<300;y++){for(int x=0;x<300;x++){if(!G(x,y)){Point p=new Point(x,y);Q=new HashSet<>();if(!S.stream().anyMatch(s->s.contains(p)))S.add(f(x,y));}}}Object[]o=S.stream().sorted((p,P)->c(p)-c(P)).toArray();s(o[0],255);s(o[1],255<<16);s(o[2],0xFF00);s(o[3],0xFFFF00);ImageIO.write(i.getSubimage(1,1,300,300),"png",new File(a));}boolean G(int x,int y){return i.getRGB(x,y)!=-1;}Set<Point>f(int x,int y){Point p=new Point(x,y);if(!Q.contains(p)&&!G(x,y)){Q.add(p);f(x-1,y);f(x+1,y);f(x,y-1);f(x,y+1);}return Q;}int c(Set<Point>s){return(int)s.stream().filter(p->G(p.x-2,p.y-1)||G(p.x-2,p.y+1)||G(p.x+1,p.y-2)||G(p.x-1,p.y-2)||G(p.x+2,p.y-1)||G(p.x+2,p.y+1)||G(p.x+1,p.y+2)||G(p.x-1,p.y+2)).count();}void s(Object o,int c){((Set<Point>)o).stream().forEach(p->{i.setRGB(p.x,p.y,c);});}

Tidak digabungkan (dan runnable; yaitu boilerplate ditambahkan):

import java.awt.Point;
import java.awt.image.BufferedImage;
import java.io.File;
import java.util.HashSet;
import java.util.Set;
import javax.imageio.ImageIO;

public class SquareCircleTriangleGear {
    public static void main(String[]args){
        try {
            new SquareCircleTriangleGear().p("filepath");
        } catch (Exception ex) {
        }
    }
    BufferedImage i;
    Set<Point>Q;
    void p(String a)throws Exception{
        i = new BufferedImage(302,302,BufferedImage.TYPE_INT_RGB);
        i.getGraphics().drawImage(ImageIO.read(new File(a)),1,1,null);
        Set<Set<Point>>set=new HashSet<>();
        for(int y=0;y<300;y++){
            for(int x = 0;x<300;x++){
                if(i.getRGB(x,y)==-1){
                    Point p = new Point(x,y);
                    Q=new HashSet<>();
                    if(!set.stream().anyMatch((s)->s.contains(p))){
                        set.add(fill(x,y));
                    }
                }
            }
        }
        Object[]o=set.stream().sorted((p,P)->c(p)-c(P)).toArray();
        s(o[0],0x0000FF);
        s(o[1],0xFF0000);
        s(o[2],0x00FF00);
        s(o[3],0xFFFF00);
        ImageIO.write(i.getSubImage(1,1,300,300), "png", new File(a));
    }
    Set<Point>fill(int x, int y){
        Point p=new Point(x,y);
        if(!Q.contains(p)&&!i.getRGB(x,y)!=-1) {
        Q.add(p);
            fill(x-1,y);
            fill(x+1,y);
            fill(x,y-1);
            fill(x,y+1);
        }
        return Q;
    }
    int c(Set<Point>s){return (int)s.stream().filter(p->isBoundary(p.x,p.y)).count();}
    boolean isBoundary(int x, int y){
        return i.getRGB(x-2,y-1)!=-1||i.getRGB(x-2,y+1)!=-1||i.getRGB(x+1,y-2)!=-1||
               i.getRGB(x-1,y-2)!=-1||i.getRGB(x+2,y-1)!=-1||i.getRGB(x+2,y+1)!=-1||
               i.getRGB(x+1,y+2)!=-1||i.getRGB(x-1,y+2)!=-1;
    }
    void s(Object o,int c){
        ((Set<Point>)o).stream().forEach(p->{i.setRGB(p.x,p.y,c);});
    }
}

Ini bekerja dengan mengulangi setiap piksel gambar dan mengisi banjir setiap kali kita mencapai "lubang". Kami menambahkan setiap hasil banjir sebagai Set<Point>a Set. Lalu kita tentukan bentuk mana yang mana. Ini dilakukan dengan melihat jumlah piksel batas bentuk. Saya mendefinisikan batas sebagai langkah ksatria menjauh dari ubin hitam, karena itu akan tetap lebih konstan antara rotasi dan semacamnya. Ketika kita melakukan ini, menjadi jelas bahwa bentuk dapat diurutkan berdasarkan nilai itu: Circle, Square, Triangle, Gear. Jadi saya mengurutkan dan mengatur semua piksel dari bentuk itu ke warna yang benar.

Perhatikan bahwa gambar yang saya tulis tidak langsung diambil dari file, karena jika saya melakukan itu, Java akan memperlakukan gambar sebagai hitam dan putih dan mengisi dengan warna tidak akan berhasil. Jadi saya harus membuat gambar saya sendiri dengan TYPE_INT_RGB(yang 1). Perhatikan juga bahwa gambar yang sedang saya kerjakan adalah 302dengan 302; ini agar algoritma jarak Knight tidak perlu khawatir tentang upaya untuk membaca di luar batas pada gambar. Saya memperbaiki perbedaan ini dalam ukuran dengan menelepon i.getSubImage(1,1,300,300). Catatan: Saya mungkin lupa untuk memperbaikinya ketika saya mengunggah gambar, dalam hal ini gambarnya 2 piksel terlalu lebar, tetapi kecuali untuk fakta ini, mereka harus benar

Fungsi ini akan menimpa file yang jalurnya dilewati. Output:

masukkan deskripsi gambar di sini masukkan deskripsi gambar di sini masukkan deskripsi gambar di sini masukkan deskripsi gambar di sini

Justin
sumber
Dapat menyimpan beberapa karakter dengan memperpendek nama kelas serta args di metode utama menjadi "a" atau serupa.
Ryan
@Ryan Itu tidak dihitung dalam hitungan. Saya hanya menghitung impor + fungsinya, sebagaimana diizinkan oleh pertanyaan.
Justin
Saya pikir saya mungkin bisa mendapatkan ini di bawah 1000 byte. Harus mengerjakan ini nanti ketika ada waktu untuk mencoba.
Justin
20

Python, 571 567 528 byte

Demikian pula dengan solusi Quincunx, itu dimulai dengan mengisi setiap bentuk dengan indeks dari 1 hingga 4. Kemudian menentukan identitas bentuk dengan jari-jari lingkaran pembatas mereka. Palet warna dikonstruksi sesuai dan gambar disimpan sebagai gambar warna yang diindeks.

EDIT: Merindukan fakta bentuk dijamin tidak menyentuh batas gambar. Lebih pendek, kalau begitu!

from PIL.Image import*;from numpy import*
I=open(sys.argv[1]).convert("P")
D=list(I.getdata())
W=300;R=range(W*W);N=range(5)
O=[[0,i,array([0,0])]for i in N];n=0
for i in R:
 if D[i]>4:
    n+=1;S=[i]
    while S:
     j=S.pop()
     if D[j]>4:D[j]=n;O[n][0]+=1;O[n][2]+=j%W,j/W;S+=[j+1,j-1,j+W,j-W]
for o in O[1:]:o[2]/=o[0];o[0]=0
for i in R:
 if D[i]:o=O[D[i]];v=(i%W,i/W)-o[2];o[0]=max(o[0],dot(v,v))
O.sort()
C=[0]*5+[255]*3+[0,255,0,0]*2;P=C[:]
for i in N:j=3*O[i][1];P[j:j+3]=C[3*i:3*i+3]
I.putdata(D);I.putpalette(P);I.save("o.png")

Mengambil nama file input pada baris perintah dan menulis output ke o.png.

Elo
sumber
2
Argh, itu jauh lebih sederhana dari apa yang saya coba lakukan. +1
Martin Ender
7

Mathematica 225


Perbarui :

OP memutuskan bahwa pendekatan ini menggunakan fungsi visi komputer, sehingga tidak lagi berjalan. Saya akan membiarkannya diposting. Mungkin seseorang mungkin menganggapnya menarik.


f@i_ := (m = MorphologicalComponents[ImageData@i];
Image@Partition[Flatten[(m)] /. 
   Append[ ReplacePart[SortBy[ComponentMeasurements[m, "Circularity"], Last], 
   {{1, 2} -> Yellow, {2, 2} -> Green, {3, 2} -> Red, {4, 2} -> Blue}], 0 -> Black], 
Dimensions[m][[2]]])

ImageData mengembalikan gambar sebagai matriks 0 dan 1.

Flatten mengubah matriks itu menjadi daftar.

Morphological Componentsmenemukan 4 cluster piksel dan menetapkan integer yang berbeda, 1, 2, 3, 4 untuk setiap piksel sesuai dengan cluster. 0 dicadangkan untuk latar belakang (hitam).

ComponentMeasurements menguji sirkularitas cluster.

Dari yang paling ke paling tidak melingkar akan selalu: lingkaran, kuadrat, segitiga, dan roda gigi.

ReplacePart mengganti setiap integer komponen dengan warna RGB masing-masing, menggunakan semacam sirkularitas.

Partition...Dimensions[m][[2]] mengambil daftar warna piksel, dan mengembalikan matriks dimensi yang sama dengan gambar input.

Image mengubah matriks warna piksel menjadi gambar berwarna.

input

{f[img1],f[img2],f[img3],f[img4]}

output

DavidC
sumber
147 karakter:f@i_:=Image[#/.Append[Thread[Ordering[Last/@ComponentMeasurements[#,"Circularity"]]->{Yellow,Green,Red,Blue}],0->Black]]&@MorphologicalComponents@i
alephalpha
Poin minor: warna Anda tidak memiliki nilai rgb yang benar. Poin utama: Saya tidak yakin saya akan menghitung ini karena tidak menggunakan perpustakaan visi komputer atau fungsi.
Hobi Calvin
"Circularity" bisa dibilang visual; Saya akan melihat apa lagi yang bisa saya lakukan. Namun, warnanya mati pada:, di {RGBColor[1, 0, 0], RGBColor[0, 1, 0], RGBColor[0, 0, 1], RGBColor[1, 1, 0]}mana 1 berkorespondensi dengan 255. Tidak ada perpustakaan yang digunakan.
DavidC
@ Calvin Hobbies Masalah ini tampaknya turun ke apakah MorphologicalComponentsmemenuhi atau melanggar aturan Anda. Begitu orang mengetahui di mana setiap piksel dimiliki, ada banyak cara, termasuk jumlah piksel mentah, untuk menentukan angka mana.
DavidC
Saya akan mengatakan bahwa itu melanggar aturan, karena sangat bisa dibilang fungsi penglihatan komputer, dan itu memberi Mathematica keuntungan yang tidak adil. Saya setuju bahwa warnanya harus benar tetapi mereka jelas terlihat di gambar Anda (merah adalah (255,0,22)ketika saya check in Paint). Saya tidak memiliki Mathematica jadi saya tidak bisa berlari untuk memastikan.
Hobi Calvin
7

Mathematica, 354 345 314 291 288

Masih bermain golf, bisa dipersingkat dengan beberapa karakter lagi, tetapi kinerjanya menjadi tak tertahankan. Menggunakan Varians untuk mengidentifikasi bentuk:

f=(w=Position[z=ImageData@Import@#,1];r=Nearest;v@x_:=Variance@N[Norm[Mean@x-#]&/@x];Image[Plus@@(ReplacePart[0z/. 0->{0,0,0},#->r[{108,124,196,115}->List@@@{Blue,Red,Green,Yellow},v@#][[1]]]&/@Rest@NestList[(m=r[w=w~Complement~#];FixedPoint[Union@@(m[#,{8,2}]&/@#)&,{#&@@w}])&,{},4])])&

Dengan jarak:

f = (w = Position[z = ImageData@Import@#, 1];
     r = Nearest; 
     v@x_ := Variance@N[Norm[Mean@x - #] & /@ x];
     Image[Plus @@ (ReplacePart[ 0 z /. 0 -> {0, 0, 0}, # -> r[{108, 124, 196, 115} -> 
                                              List @@@ {Blue, Red, Green, Yellow}, v@#][[1]]] & /@
     Rest@NestList[(m = r[w = w~ Complement~#];
                   FixedPoint[Union @@ (m[#, {8, 2}] & /@ #) &, {# & @@ w}]) &
                   , {}, 4])]) &

Pengujian:

s = {"http://i.stack.imgur.com/Oa2O1.png", "http://i.stack.imgur.com/C6IKR.png", 
     "http://i.stack.imgur.com/YZfc6.png", "http://i.stack.imgur.com/F1ZDM.png", 
     "http://i.stack.imgur.com/chJFi.png", "http://i.stack.imgur.com/DLM3y.png"};
Partition[f /@ s, 3] // Grid

Grafik Mathematica

Ini benar-benar tanpa bulu. Akan menambahkan penjelasan nanti:

findOneZone[{universe_List, lastZone_List}] :=
 Module[{newUniverse, proximityFindFunc, seedElement},
  newUniverse = Complement[universe, lastZone];
  proximityFindFunc = Nearest@newUniverse;
  seedElement = {First@newUniverse};
  {newUniverse, FixedPoint[Union @@ (proximityFindFunc[#, {8, 2}] & /@ #) &, seedElement]}]

colorAssign[zone_List] :=
 Module[{
   vlist = {108, 124, 196, 115},
   cols = List @@@ {Blue, Red, Green, Yellow},
   centerVariance},
  centerVariance[x_List] := Variance@N[Norm[Mean@x - #] & /@ x];
  First@Nearest[vlist -> cols, centerVariance@zone]]

colorRules[zones_List] := (# -> colorAssign[#] & /@ zones)

main[urlName_String] := 
 Module[{pixels, FgPixelPositions, rawZones, zones},
  pixels = ImageData@Import@urlName;
  FgPixelPositions = Position[pixels, 1];
  (*fill and separate the regions*)
  rawZones = NestList[findOneZone[#] &, {FgPixelPositions, {}}, 4];
  zones = Rest[rawZones][[All, 2]];
  (*Identify,colorize and render*)
  Image@ReplacePart[ConstantArray[{0, 0, 0}, Dimensions@pixels], 
    colorRules[zones]]]

s = {"http://i.stack.imgur.com/Oa2O1.png"};
main /@ s
Belisarius
sumber
2

Python, 579 577 554 514 502 501 byte

Untuk setiap bentuk, isi banjir, lalu hitung jarak antara pusat massa dan titik terjauh.

maka permukaan bentuk yang sebenarnya dibandingkan dengan permukaan segitiga, bujur sangkar, cakram atau roda yang akan memiliki ukuran yang sama.

impor matematika ; dari PIL . Impor gambar *; A , R , _ , I = abs , range ( 300 ), 255 , open ( sys . Argv [ 1 ]). convert ( 'P' ); Q = I . load () untuk j di R : untuk i di R : jika Q [ 

 
  i , j ] == _ : 
   X , Y , s , z , p = 0 , 0 , 0 , [], [( i , j )] sementara p : 
    a , b = n = p . pop () jika tidak ( Q [ n ]! = _ atau n dalam z ): 
     X + = a ; Y + =
   
     b ; z + = [ n ]; p + = [( a , b - 1 ), ( a + 1 , b ), ( a , b + 1 ), ( a - 1 , b )]; s + = 1 
   r = maks ([ matematika . hipot ( X / s - x , Y / s - y ) untuk x , y di z ]); C = { 1 : A ( s - ( 1.4 * r ) ** 2 ), 2 : A ( s - r * r / 3 ), 3 : A ( s - matematika . Pi * r * r ), 4 : A ( s - 2.5 * r * r )} untuk p dalam z
   : 
    Q [ p ] = min ( C , kunci = C . Mendapatkan ) 
saya . putpalette ([ 0 , 0 , 0 , _ ] * 3 + [ _ , _ , 0 ]) 
saya . tampilkan ()
pelaku diet
sumber
1

C # 1086 byte

Namun solusi penimbunan lain, hanya untuk catatan karena tidak ada versi C # di sini. Seperti Quincunx saya ingin membuktikan diri bahwa saya dapat melakukannya dan tidak ada banyak perbedaan dengan pendekatannya di Jawa.

  • Solusi ini tidak menggunakan rekursi (tetapi setumpuk) karena saya terus berlari ke StackOverflows.
  • Deteksi borderpixels disederhanakan dengan melihat 4 piksel berikutnya, jika salah satu dari mereka berwarna hitam, saat ini adalah piksel perbatasan.

Ini menerima setiap format gambar.

  • Parameter 1 = InputPath
  • Parameter 2 = OutputPath

Mungkin dapat dilucuti beberapa charachters dengan menghapus semua hal-hal statis dan membuat instance Program.

Versi yang Dapat Dibaca:

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.Linq;

class Program
{
    static Bitmap img;
    static int w, h;
    static ISet<Point> pointsDone = new HashSet<Point>();
    static void Main(string[] a)
    {
        img = new Bitmap(a[0]);
        w = img.Width;
        h = img.Height;
        Bitmap clone = new Bitmap(w,h, PixelFormat.Format32bppArgb);
        Graphics.FromImage(clone).DrawImage(img, 0, 0, w, h);
        img = clone;




        Color[] colors = new[] { Color.Blue, Color.Red, Color.Green, Color.Yellow };

        var shapes = new List<ISet<Tuple<bool, Point>>>();
        for(int x=0;x<w;x++)
            for (int y = 0; y < h; y++)
            {
                Point p = new Point(x, y);
                if (pointsDone.Add(p) && _isWhitePixel(p))
                    shapes.Add(_detectShape(p));
            }
        int index = 0;
        foreach (var shp in shapes.OrderBy(shp => shp.Count(item => item.Item1)))
        {
            foreach (var pixel in shp)
                img.SetPixel(pixel.Item2.X, pixel.Item2.Y, colors[index]);
            index++;
        }

        img.Save(a[1]);
    }

    private static ISet<Tuple<bool, Point>> _detectShape(Point p)
    {
        var todo = new Stack<Point>(new[] { p });
        var shape = new HashSet<Tuple<bool, Point>>();
        do
        {
            p = todo.Pop();
            var isBorderPixel = false;
            foreach (var n in new[] { new Point(p.X + 1, p.Y), new Point(p.X - 1, p.Y), new Point(p.X, p.Y + 1), new Point(p.X, p.Y - 1) })
                if (_isWhitePixel(n))
                {
                    if (pointsDone.Add(n))
                        todo.Push(n);
                }
                else isBorderPixel = true; // We know we are at the border of the shape
            shape.Add(Tuple.Create(isBorderPixel, p));

        } while (todo.Count > 0);
        return shape;
    }

    static bool _isWhitePixel(Point p)
    {
        return img.GetPixel(p.X, p.Y).ToArgb() == Color.White.ToArgb();
    }
}

Golf:

using System;using System.Collections.Generic;using System.Drawing;using System.Drawing.Imaging;using System.Linq;class P{static Bitmap a;static int w,h;static ISet<Point> d=new HashSet<Point>();static void Main(string[] q){a=new Bitmap(q[0]);w=a.Width;h=a.Height;var c=new Bitmap(w,h,PixelFormat.Format32bppArgb);Graphics.FromImage(c).DrawImage(a,0,0,w,h);a=c;var e=new[]{Color.Blue,Color.Red,Color.Green,Color.Yellow};var f=new List<ISet<dynamic>>();for(int x=0;x<w;x++)for(int y=0;y<h;y++){Point p=new Point(x,y);if (d.Add(p)&&v(p))f.Add(u(p));}int i=0;foreach(var s in f.OrderBy(s=>s.Count(item=>item.b))){foreach(var x in s)a.SetPixel(x.p.X,x.p.Y,e[i]);i++;}a.Save(q[1]);}private static ISet<dynamic> u(Point p){var t=new Stack<Point>(new[]{p});var s=new HashSet<dynamic>();do{p=t.Pop();var b=false;foreach(var n in new[]{new Point(p.X+1,p.Y),new Point(p.X-1,p.Y),new Point(p.X,p.Y+1),new Point(p.X,p.Y-1)})if(v(n)){if (d.Add(n))t.Push(n);}else b=true;s.Add(new{b,p});}while (t.Count>0);return s;}static bool v(Point p){return a.GetPixel(p.X,p.Y).ToArgb()==Color.White.ToArgb();}}
CSharpie
sumber