Hình vuông, hình tròn, hình tam giác, bánh răng?


69

Sử dụng Algodoo và Paint Tôi đã tạo ra sáu hình ảnh đơn sắc 300 × 300 này với bốn hình dạng thuận tiện:

Hình 1 Hình 2 Hình 3 Hình 4 Hình 5 Hình 6

Lớp hình ảnh này có các thuộc tính sau:

  • Chúng luôn có kích thước 300 × 300 pixel, đơn sắc (chỉ đen và trắng) và có chính xác bốn vùng trắng tương ứng với hình vuông, hình tròn, hình tam giác và bánh răng.
  • Các hình dạng không bao giờ trùng nhau hoặc chạm vào nhau, cũng không chạm vào đường viền hình ảnh hoặc đi ra khỏi giới hạn.
  • Các hình dạng luôn có cùng kích thước, nhưng chúng có thể được xoay và định vị theo bất kỳ cách nào.

(Các hình dạng cũng có diện tích bằng nhau, mặc dù khi raster như thế này, số pixel của chúng không có khả năng tương đương chính xác.)

Thử thách

Viết chương trình hoặc chức năng ngắn nhất có thể có trong tên tệp của hình ảnh đó và biến tất cả các pixel trắng ...

  • màu đỏ (255, 0, 0)nếu chúng ở trong hình vuông.
  • màu xanh (0, 0, 255)nếu chúng ở trong vòng tròn.
  • màu xanh lá cây (0, 255, 0)nếu chúng nằm trong tam giác.
  • màu vàng (255, 255, 0)nếu chúng ở trong bánh răng.

ví dụ

Hình 1 màu

Chi tiết

Chương trình của bạn nên hoạt động hiệu quả cho tất cả các hình ảnh đầu vào có thể. (Chỉ có hình ảnh đơn sắc 300 × 300 hợp lệ sẽ được nhập vào.) Sáu hình ảnh tôi đã cung cấp chỉ là ví dụ, bạn không thể mã hóa đầu ra của chúng vào chương trình của mình.

Bạn không được sử dụng các thư viện hoặc chức năng thị giác máy tính, tích hợp hoặc bên ngoài. Vấn đề là làm điều này bằng cách sử dụng các hoạt động cấp pixel của riêng bạn. Bạn có thể sử dụng các thư viện hình ảnh đơn giản cho phép bạn mở và sửa đổi hình ảnh (ví dụ PIL cho Python).

Bạn có thể sử dụng bất kỳ định dạng tệp hình ảnh lossless phổ biến nào cho đầu vào và đầu ra miễn là bạn tuân theo bảng màu.

Bạn có thể lấy tên tệp hình ảnh làm đối số chức năng, từ stdin hoặc từ dòng lệnh. Hình ảnh đầu ra có thể được lưu vào một tệp mới, cùng một tệp hoặc được hiển thị đơn giản.

Chấm điểm

Việc gửi với ít byte nhất sẽ thắng. Tôi có thể kiểm tra bài nộp với hình ảnh bổ sung để xác định tính hợp lệ của chúng.


Chúng ta có thể giả sử đầu vào là đen trắng không có khử răng cưa không? Nếu không, chúng ta có thể loại bỏ khử răng cưa khỏi các đầu vào khử răng cưa không?
John Dvorak

@JanDvorak Vâng. Theo đơn sắc, ý tôi là chỉ có màu đen và trắng, vì vậy không thể khử răng cưa.
Sở thích của Calvin

1
Chúng tôi có thể yêu cầu một định dạng đầu vào cụ thể chính xác hơn là chỉ một phần mở rộng tập tin không? Cụ thể, tôi muốn tôi nhập liệu PBM ASCII mà không có bất kỳ nhận xét nào bên trong.
John Dvorak

12
Vì vậy, ... tôi đã cố gắng giải quyết điều này, và tôi đã kết thúc với hình ảnh này . Không thực sự chắc chắn làm thế nào, nhưng hey, nó trông lạ mắt. : P
Doorknob

2
Tôi không muốn đăng giải pháp của mình vì đó là ý tưởng giống như của Ell nhưng tệ hơn. Nhưng tôi chỉ muốn nói rằng đây là một thử thách nhỏ thú vị để thực hiện :)
Chris Burt-Brown

Câu trả lời:


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_)

Đây là một niềm vui!

Tôi đã sử dụng lại phần linh kiện được kết nối mà tôi đã sử dụng cho thử thách "Tôi ở trong phòng lớn nhất" và sử dụng tỷ lệ giữa khoảng cách trung bình và tối đa của tất cả các điểm đến trung tâm của mỗi thành phần. Tôi giải quyết vấn đề này, vì nó bất biến cả tỷ lệ và xoay, và dường như đủ tốt để phân biệt giữa các hình dạng như đã cho. Xếp hạng giá trị này từ thấp đến cao cho tôi vòng tròn thứ tự, bánh răng, hình vuông và hình tam giác, được sử dụng để hoán vị bản đồ màu.

Hiển thị kết quả bằng addon viewmap. Không có hộp công cụ nào được sử dụng ngoại trừ việc đọc và xuất tệp.

Sự mạnh mẽ dường như không phải là một yêu cầu, điều này sẽ mất 18 byte. Thêm 2 khoảng trắng không cần thiết, được thay thế &.>bằng &>in ratio&.:bằng cách &:bổ sung thêm 2 byte.

Tăng rất lớn cả về độ ngắn và hiệu suất của compviệc sử dụng dịch chuyển thay vì cut( ;.). Bằng cách này, hình ảnh được sao chép và dịch chuyển theo cả 8 hướng thay vì quét nó bằng cửa sổ 3x3.

Các idchức năng rất phức tạp cho những gì nó cần phải làm. Bây giờ, nó gán id cho pixel trong các đối tượng bằng cách nhân hình ảnh với một mảng các số duy nhất, do đó đặt BG thành 0.

Mã giải thích thêm một chút:

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

Điều này là một chút dài để giải thích chi tiết, nhưng sẽ làm nếu có lãi.


Các pixel phía trên bên phải được đảm bảo là bg. Theo OP "Các hình dạng không bao giờ trùng nhau hoặc chạm vào nhau, cũng không chạm vào đường viền hình ảnh hoặc đi ra khỏi giới hạn."
Tiến sĩ belisarius

Cảm ơn, điều đó hữu ích. (thực ra tôi có nghĩa là pixel phía trên bên trái, điểm đầu tiên trong ravel). Điều này giúp loại bỏ phát hiện nền (22 byte).
jpjacobs

Giảm đáng kể thời lượng và tăng hiệu suất :)
jpjacobs

29

Toán học, 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]]])&

Ung dung:

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]]]
) &

Tôi có thể tiết kiệm thêm 6 byte bằng cách chuyển m=1.Mean@a;m=#-m&/@a;vào m=#-Mean@a&/@a;, nhưng điều đó làm tăng đáng kể thời gian thực hiện, gây khó chịu cho việc kiểm tra. (Lưu ý, rằng đây là hai optimisations: kéo ra việc tính toán Mean@ara khỏi vòng lặp . Sử dụng các loại chính xác mang tính biểu tượng thay vì số dấu chấm động Điều thú vị là sử dụng các loại chính xác là rất nhiều quan trọng hơn tính toán giá trị trung bình trong mỗi lần lặp.)

Vì vậy, đây là cách tiếp cận số ba:

  • Phát hiện các khu vực bằng cách lấp lũ.
  • Tìm trung tâm gần đúng của từng khu vực bằng cách lấy trung bình tất cả các tọa độ pixel.
  • Bây giờ, đối với tất cả các pixel trong hình, hãy vẽ khoảng cách từ góc tới trung tâm đó:

    nhập mô tả hình ảnh ở đây

    Hình tam giác có 3 cực đại rõ ràng, hình vuông 4, bánh răng 16 và hình tròn có hàng tấn, do dao động răng cưa về bán kính không đổi.

  • Chúng tôi tìm thấy số lượng cực đại bằng cách nhìn vào các lát 300 pixel (được sắp xếp theo góc) và đếm các lát trong đó pixel ở vị trí 150là tối đa.
  • Sau đó, chúng tôi chỉ tô màu tất cả các pixel tùy thuộc vào số lượng đỉnh (vòng tròn là bất cứ thứ gì trên 16 và thường mang lại khoảng 20 đỉnh, do kích thước của các lát).

Chỉ dành cho bản ghi, nếu tôi sử dụng ý tưởng của Ell và chỉ cần sắp xếp các vùng theo khoảng cách lớn nhất giữa bất kỳ pixel và trung tâm nào, tôi có thể thực hiện việc này trong 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]]])&

Nhưng tôi không có ý định cạnh tranh với điều đó, miễn là mọi người khác đang sử dụng thuật toán ban đầu của riêng họ, thay vì đánh golf những người khác.


Giải pháp thú vị nhất!
CSharpie

25

Java, 1204 1132 1087 1076

Chỉ để chứng minh với bản thân rằng tôi có thể làm điều này.

Tôi đã bao gồm nhập khẩu ngay bên cạnh các khai báo chức năng; những thứ này sẽ phải ở ngoài lớp để làm việc này:

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

Ungolfed (và có thể chạy được; tức là thêm bản tóm tắt):

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

Điều này hoạt động bằng cách lặp lại qua từng pixel của hình ảnh và lấp đầy mỗi khi chúng ta đạt đến một "lỗ hổng". Chúng tôi thêm từng kết quả lấp đầy lũ là Set<Point>a Set. Sau đó, chúng tôi xác định hình dạng nào. Điều này được thực hiện bằng cách nhìn vào số pixel pixel của hình dạng. Tôi đã xác định ranh giới khi một hiệp sĩ di chuyển ra khỏi một ô màu đen, vì điều đó sẽ không đổi giữa các lần xoay và như vậy. Khi chúng ta làm điều này, nó trở nên rõ ràng rằng các hình dạng có thể được sắp xếp theo giá trị đó: Circle, Square, Triangle, Gear. Vì vậy, tôi sắp xếp và đặt tất cả các pixel của hình dạng đó thành màu chính xác.

Lưu ý rằng hình ảnh tôi đang viết không được lấy trực tiếp từ tệp, vì nếu tôi làm điều đó, Java sẽ coi hình ảnh là đen trắng và tô màu sẽ không hoạt động. Vì vậy, tôi phải tạo ra hình ảnh của riêng tôi với TYPE_INT_RGB(đó là 1). Cũng lưu ý rằng hình ảnh tôi đang làm việc trên là 302do 302; điều này là để thuật toán khoảng cách của Hiệp sĩ không cần phải lo lắng về việc cố gắng đọc các giới hạn trên hình ảnh. Tôi khắc phục sự khác biệt về kích thước bằng cách gọi i.getSubImage(1,1,300,300). Lưu ý: Tôi có thể đã quên sửa lỗi này khi tôi tải lên hình ảnh, trong trường hợp hình ảnh quá rộng 2 pixel, nhưng ngoại trừ thực tế này, chúng phải chính xác

Hàm sẽ ghi đè lên tệp có đường dẫn được truyền vào. Kết quả:

nhập mô tả hình ảnh ở đây nhập mô tả hình ảnh ở đây nhập mô tả hình ảnh ở đây nhập mô tả hình ảnh ở đây


Có thể lưu một vài ký tự bằng cách rút ngắn tên lớp cũng như đối số trong phương thức chính thành "a" hoặc tương tự.
Ryan

@Ryan Những người không được tính trong số đếm. Tôi chỉ tính số nhập khẩu + các chức năng, như được cho phép bởi câu hỏi.
Justin

Tôi nghĩ rằng tôi có thể có được điều này dưới 1000 byte. Phải làm việc này sau khi có thời gian để thử.
Justin

20

Con trăn 571 567 528 byte

Tương tự như giải pháp của Quincunx, nó bắt đầu bằng cách lấp đầy mỗi hình dạng với chỉ số từ 1 đến 4. Sau đó, nó xác định danh tính của các hình bằng bán kính của vòng tròn giới hạn của chúng. Một bảng màu được xây dựng tương ứng và hình ảnh được lưu dưới dạng hình ảnh màu được lập chỉ mục.

EDIT: Bỏ lỡ thực tế các hình dạng được đảm bảo không chạm vào đường viền hình ảnh. Nó ngắn hơn, sau đó!

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")

Lấy tên tệp đầu vào trên dòng lệnh và ghi đầu ra vào o.png.


2
Argh, điều đó đơn giản hơn nhiều so với những gì tôi đang cố gắng làm. +1
Martin Ender

7

Toán học 225


Cập nhật :

OP đã quyết định rằng phương pháp này sử dụng các chức năng thị giác của máy tính, do đó, nó không còn hoạt động nữa. Tôi sẽ để nó được đăng tuy nhiên. Có lẽ ai đó có thể tìm thấy nó quan tâm.


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 trả về hình ảnh dưới dạng ma trận 0 và 1.

Flatten chuyển đổi ma trận đó thành một danh sách.

Morphological Componentstìm thấy 4 cụm pixel và gán một số nguyên riêng biệt, 1, 2, 3, 4 cho mỗi pixel theo cụm. 0 được dành riêng cho nền (màu đen).

ComponentMeasurements kiểm tra tính tuần hoàn của các cụm.

Từ hầu hết đến vòng tròn nhỏ nhất sẽ luôn là: hình tròn, hình vuông, hình tam giác và bánh răng.

ReplacePart thay thế từng số nguyên thành phần bằng màu RGB tương ứng, sử dụng sắp xếp vòng tròn.

Partition...Dimensions[m][[2]] lấy danh sách các màu pixel và trả về một ma trận có cùng kích thước với hình ảnh đầu vào.

Image chuyển đổi ma trận màu pixel thành hình ảnh màu.

đầu vào

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

đầu ra


147 ký tự:f@i_:=Image[#/.Append[Thread[Ordering[Last/@ComponentMeasurements[#,"Circularity"]]->{Yellow,Green,Red,Blue}],0->Black]]&@MorphologicalComponents@i
alephalpha

Điểm nhỏ: màu sắc của bạn không có giá trị rgb chính xác. Điểm chính: Tôi không chắc chắn tôi sẽ coi đây là việc không sử dụng các thư viện hoặc chức năng thị giác máy tính.
Sở thích của Calvin

"Thông tư" được cho là trực quan; Tôi sẽ xem những gì tôi có thể làm. Tuy nhiên, các màu đã chết trên : {RGBColor[1, 0, 0], RGBColor[0, 1, 0], RGBColor[0, 0, 1], RGBColor[1, 1, 0]}, trong đó 1 tương ứng với 255. Không có thư viện nào được sử dụng.
DavidC

@ Calvin'sHob sở thích Vấn đề dường như đi đến việc MorphologicalComponentsthỏa mãn hay vi phạm quy tắc của bạn. Khi người ta biết mỗi pixel thuộc về cụm nào, có nhiều cách, bao gồm cả số pixel thô, để xác định hình nào là hình nào.
DavidC

Tôi sẽ nói rằng nó vi phạm các quy tắc, vì nó rất có thể là một chức năng thị giác máy tính, và nó mang lại cho Mathicala một lợi thế không công bằng. Tôi đồng ý rằng màu sắc phải chính xác nhưng chúng nhìn rõ trong hình ảnh của bạn (màu đỏ là (255,0,22)khi tôi kiểm tra Paint). Tôi không có Mathicala nên tôi không thể chạy để đảm bảo.
Sở thích của Calvin

7

Toán học, 354 345 314 291 288

Vẫn chơi golf, có thể rút ngắn thêm một vài ký tự, nhưng hiệu suất trở nên không thể chịu đựng được. Sử dụng phương sai để xác định hình dạng:

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])])&

Với khoảng cách:

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])]) &

Kiểm tra:

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

Đồ họa toán học

Ở đây nó hoàn toàn vô căn cứ. Sẽ thêm giải thích sau:

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

2

Python, 579 577 554 514 502 501 byte

Đối với mỗi hình dạng, lấp đầy nó, sau đó tính khoảng cách giữa tâm và điểm xa nhất.

sau đó bề mặt thực của hình được so sánh với bề mặt của hình tam giác, hình vuông, đĩa hoặc bánh xe có cùng kích thước.

toán nhập khẩu ; từ PIL . Nhập ảnh *; A , R , _ , I = abs , phạm vi ( 300 ), 255 , mở ( sys . Argv [ 1 ]). chuyển đổi ( 'P' ); Q = tôi . tải () cho j trong R : cho i trong R : if Q [ 

 
  i , j ] == _ : 
   X , Y , s , z , p = 0 , 0 , 0 , [], [( i , j )] trong khi p : 
    a , b = n = p . pop () nếu không ( Q [ n ]! = _ hoặc n trong z ): 
     X + = a ; Y + =
   
     b ; z + = [ n ]; p + = [( a , b - 1 ), ( a + 1 , b ), ( a , b + 1 ), ( a - 1 , b )]; s + = 1 
   r = max ([ toán học . hypot ( X / s - x , Y / s - y ) cho x , y trong z ]); C = { 1 : A ( s - ( 1.4 * r ) ** 2 ), 2 : A ( s - r * r / 3 ), 3 : A ( s - math . Pi * r * r ), 4 : A ( s - 2,5 * r * r )} cho p theo z
   : 
    Q [ p ] = min ( C , chìa khóa = C . Được ) 
tôi . putpalette ([ 0 , 0 , 0 , _ ] * 3 + [ _ , _ , 0 ]) 
tôi . hiển thị ()

1

C # 1086 byte

Một giải pháp chống ngập lụt khác, chỉ dành cho hồ sơ vì không có phiên bản C # ở đây. Giống như Quincunx tôi muốn chứng minh bản thân rằng tôi có thể làm được và không có nhiều khác biệt so với cách tiếp cận của anh ấy trong Java.

  • Giải pháp này không sử dụng bất kỳ đệ quy nào (mà là một ngăn xếp) vì tôi cứ chạy vào StackOverflows.
  • Việc phát hiện Borderpixels được đơn giản hóa bằng cách nhìn vào 4 pixel tiếp theo, nếu bất kỳ pixel nào có màu đen thì hiện tại là pixel pixel.

Nó chấp nhận mọi hình ảnh.

  • Tham số 1 = InputPath
  • Tham số 2 = OutputPath

Nó có thể có thể được gỡ bỏ một vài ký tự bằng cách loại bỏ tất cả các nội dung tĩnh và tạo một thể hiện của Chương trình.

Phiên bản dễ đọc:

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

Chơi gôn

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();}}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.