スクエア、サークル、トライアングル、…ギア?


69

AlgodooとPaintを使用して、次の4つの便利な形状の6つの300×300モノクロ画像を作成しました。

画像1 画像2 画像3 画像4 画像5 画像6

このクラスの画像には、次のプロパティがあります。

  • これらは常に300×300ピクセル、単色(白黒のみ)で、正方形、円、三角形、歯車に対応する正確に4つの白い領域があります。
  • シェイプが互いに重なり合ったり、接触したりすることはありません。また、画像の境界に接触したり、境界から外れたりすることもありません。
  • 形状のサイズは常に同じですが、任意の方法で回転および配置できます。

(シェイプの面積も等しくなりますが、このようにラスタ化すると、ピクセル数が正確に等しくなる可能性は低くなります。)

チャレンジ

そのような画像のファイル名を取り、すべての白いピクセルを回す可能な最短のプログラムまたは関数を書きます...

  • (255, 0, 0)正方形にある場合は赤。
  • (0, 0, 255)サークル内にある場合は青。
  • (0, 255, 0)三角形の中にある場合は緑。
  • (255, 255, 0)ギアにいる場合は黄色。

例えば

色付きの画像1

詳細

プログラムは、考えられるすべての入力画像に対して効果的に機能するはずです。(有効な300×300のモノクロ画像のみが入力されます。)私が提供した6つの画像は単なる例であり、プログラムに出力をハードコードすることはできません。

組み込みまたは外部のコンピュータービジョンライブラリまたは関数を使用することはできません。ポイントは、独自のピクセルレベルの操作を使用してこれを行うことです。画像を簡単に開いて変更できる画像ライブラリを使用できます(例:PIL for Python)。

カラースキームに固執する限り、入力および出力に一般的なロスレス画像ファイル形式を使用できます。

画像ファイル名を関数の引数として、stdin、またはコマンドラインから取得できます。出力画像は、新しいファイル、同じファイルに保存するか、単に表示することができます。

得点

最少バイト送信が勝ちです。追加の画像を使用して提出物をテストし、それらの有効性を判断できます。


入力がアンチエイリアスなしの白黒であると仮定できますか?そうでない場合、アンチエイリアス入力からアンチエイリアスを削除できますか?
ジョンドヴォルザーク14年

@JanDvorakはい。単色とは、白黒のみを意味するため、アンチエイリアスはできません。
カルビンの趣味14年

1
ファイル拡張子だけでなく、より正確に特定の入力形式が必要な場合がありますか?つまり、コメントなしのASCII PBM入力が欲しいのです。
ジョンドヴォルザーク14年

12
だから...私はこれを解決しようとしていて、このイメージになりました。確かにわからないが、ちょっと、派手に見える。:P
ドアノブ

2
Ellのアイデアと同じですが、さらに悪いことなので、ソリューションを投稿したくありません。しかし、私はこれを行うには楽しい小さな挑戦だったと言いたいです:)
クリスバートブラウン14年

回答:


8

J- 246,224 185バイト

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

これは楽しいものでした!

「最大の部屋にいる」チャレンジで使用した接続コンポーネントパーツを再利用し、各コンポーネントの中心までのすべてのポイントの平均距離と最大距離の比率を使用しました。スケールと回転の両方に不変であり、与えられた形状を区別するのに十分なように見えるので、私はこれに決めました。この値を低から高にランク付けすると、カラーマップの並べ替えに使用される円、歯車、正方形、三角形の順序がわかります。

ビューマップアドオンを使用して結果を表示します。ファイルの読み取りと出力を除き、ツールボックスは使用されません。

堅牢性は要件ではないようです。これにより、18バイトが削減されます。置き換え2つの以上の不要なスペース&.>によって&>ratio&.:することにより&:、他の2バイトのためdcentに。

()のcomp代わりにシフトを使用すると、短さとパフォーマンスの両方が大幅に向上します。この方法では、3x3ウィンドウでスキャンするのではなく、8方向すべてに画像が複製およびシフトされます。cut;.

このid機能は、実行する必要があるために途方もなく複雑でした。これで、画像に一意の数字の配列を乗算することにより、オブジェクトのピクセルにidを割り当て、BGをゼロに設定します。

もう少し説明したコード:

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

これは、詳細に説明するには少し長いですが、興味があれば行います。


右上のピクセルはbgであることが保証されています。OPによると、「シェイプが重なり合ったり、互いに接触したりすることはありません。また、画像の境界に接触したり、境界を越えたりすることもありません。」
ベリサリウス博士14年

ありがとう、それは役に立ちます。(実際には、左上のピクセル、ラヴェルの最初のピクセルを意味しました)。これにより、バックグラウンド検出が削除されます(22バイト)。
jpjacobs 14年

長さが大幅に短縮され、パフォーマンスが向上しました:)
jpjacobs

29

Mathematica、459 392バイト

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

ゴルフをしていない:

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

私は回して6つの以上のバイトを救うことができるm=1.Mean@a;m=#-m&/@a;m=#-Mean@a&/@a;、それは非常にテストのために迷惑である実行時間を、吹きます。(これは、2つの最適化であることに注意してください:の計算引き出しMean@aループのアウトし、代わりに浮動小数点数の正確なシンボリック・タイプを使用して興味深いことに、正確なタイプの使用は、多くの反復ごとに平均値を計算するよりも重要)。

したがって、これはアプローチ番号3です。

  • 洪水でエリアを検出します。
  • すべてのピクセル座標を平均することにより、各領域のおおよその中心を見つけます。
  • 形状内のすべてのピクセルについて、対角からその中心までの距離をプロットしましょう:

    ここに画像の説明を入力してください

    三角形には3つの明確な最大値、正方形4、歯車16があり、円には一定の半径に関するエイリアシング変動のためにトンがあります。

  • 300ピクセルのスライス(角度順)を見て最大数を見つけ、位置のピクセル150が最大になるスライスを数えます。
  • 次に、ピークの数に応じてすべてのピクセルに色を付けます(円は16を超えるもので、スライスのサイズにより通常は約20のピークが得られます)。

記録のために、エルのアイデアを使用し、ピクセルと中心間の最大距離で領域を並べ替える場合、342バイトでこれを行うことができます:

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

しかし、他の全員が独自のアルゴリズムを使用している限り、他の人のアルゴリズムを打ち負かすのではなく、私はそれと競争するつもりはありません。


最も興味深いソリューション!
CSharpie 14年

25

Java、1204 1132 1087 1076

ちょうどその自分自身に証明するために、私はこれを行うことができます。

関数宣言のすぐ隣にインポートを含めました。これらが機能するためには、クラスの外になければなりません。

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

ゴルフされていない(および実行可能、つまり定型句が追加された):

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

これは、画像のすべてのピクセルを反復処理し、「穴」に達するたびに塗りつぶすことで機能します。各塗りつぶしの結果をaとしてa Set<Point>に追加しSetます。次に、どの形状がどれであるかを判断します。これは、シェイプの境界ピクセルの数を調べることで行われます。黒のタイルからの騎士の動きとして境界を定義しました。なぜなら、それは回転などの間でより一定のままだからです。これを行うと、円、正方形、三角形、歯車などの値で形状をソートできることが明らかになります。そのため、その形状のすべてのピクセルを正しい色に並べ替えて設定します。

書き込み先の画像はファイルから直接取得されないことに注意してください。これを行うと、Javaは画像を白黒として扱い、色の塗りつぶしは機能しません。そのため、TYPE_INT_RGB(である1)を使用して独自のイメージを作成する必要があります。また、私が作業しているイメージは302by であることに注意してください302。これは、ナイトの距離アルゴリズムが画像の範囲外の読み取りを試みることを心配する必要がないようにするためです。このサイズの不一致は、を呼び出して修正しますi.getSubImage(1,1,300,300)注:画像をアップロードしたときにこれを修正するのを忘れている場合があります。この場合、画像の幅は2ピクセルです。ただし、この事実を除き、正しいはずです。

この関数は、パスが渡されたファイルを上書きします。出力:

ここに画像の説明を入力してください ここに画像の説明を入力してください ここに画像の説明を入力してください ここに画像の説明を入力してください


mainメソッドのクラス名と引数を「a」などに短縮することにより、数文字を節約できます。
ライアン14年

@Ryanこれらはカウントには含まれません。質問で許可されているように、インポートと関数のみをカウントします。
ジャスティン14年

1000バイト未満でこれを取得できると思います。後で試す時間があるときに、これに取り組む必要があります。
ジャスティン14年

20

Python、 571 567 528バイト

Quincunxのソリューションと同様に、1〜4のインデックスで各形状を塗りつぶします。次に、境界円の半径によって形状の同一性を判断します。それに応じてカラーパレットが構築され、イメージはインデックスカラーイメージとして保存されます。

編集:図形が画像の境界に触れないことが保証されているという事実を見逃しました。短くなります!

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

コマンドラインで入力ファイル名を取得し、出力をに書き込みますo.png


2
ああ、それは私がやろうとしていることよりもずっと簡単です。+1
マーティンエンダー14年

7

Mathematica 225


更新

OPは、このアプローチではコンピュータービジョン機能を使用することを決定したため、現在は実行されていません。ただし、投稿したままにします。おそらく誰かが興味のあるものを見つけるかもしれません。


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 イメージを0と1のマトリックスとして返します。

Flatten その行列をリストに変換します。

Morphological Componentsピクセルの4つのクラスターを見つけ、クラスターに従って各ピクセルに個別の整数1、2、3、4を割り当てます。0は(黒)背景用に予約されています。

ComponentMeasurements クラスターの円形性をテストします。

円形から正方形、三角形、歯車まで、常に最大から最小の円形になります。

ReplacePart 円形度ソートを使用して、各コンポーネント整数をそれぞれのRGBカラーに置き換えます。

Partition...Dimensions[m][[2]] はピクセルの色のリストを取り、入力画像と同じ次元の行列を返します。

Image ピクセルカラーのマトリックスをカラー画像に変換します。

入力

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

出力


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

軽微な点:色に正しいRGB値がありません。主なポイント:これをコンピュータービジョンライブラリまたは関数を使用していないと見なすかどうかわかりません。
カルビンの趣味14年

「円形性」はほぼ間違いなく視覚的です。他に何ができるか見ていきます。ただし、色は次のとおりです{RGBColor[1, 0, 0], RGBColor[0, 1, 0], RGBColor[0, 0, 1], RGBColor[1, 1, 0]}。1は255に対応します。ライブラリは使用されませんでした。
DavidC 14年

@ Calvin'sHobbies問題はMorphologicalComponents、ルールを満たしているか違反しているかにかかっているようです。各ピクセルがどのクラスターに属しているかがわかれば、ピクセルの生のカウントを含む多くの方法があり、どの図がどれであるかを決定します。
DavidC 14年

非常に間違いなくコンピュータービジョン関数であり、Mathematicaに不公平な利点があるため、ルールに違反していると言います。色は正しいはずですが、画像でははっきりと見えます(赤は(255,0,22)ペイントでチェックしたときです)。Mathematicaを持っていないので、実行することはできません。
カルビンの趣味14年

7

Mathematica、354 345 314 291 288

まだゴルフをしていると、さらに数文字チャーを短くすることができますが、パフォーマンスは耐えられなくなります。Varianceを使用して形状を識別します。

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

間隔あり:

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

テスト:

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

Mathematicaグラフィックス

ここでは完全に無制限です。後で説明を追加します:

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

パイソン、579の 577 554 514 502 501バイト

各形状について、それを塗りつぶし、重心と最も遠い点の間の距離を計算します。

次に、形状の実際の表面を、同じサイズの三角形、正方形、ディスク、またはホイールの表面と比較します。

インポート数学; PIL から画像のインポート*; R _ I = ABS 範囲300 )、255 オープンSYS ARGV [ 1 ])。変換'P' ); Q = I load ()for j in R for i in R if Q [ 

 
  I J ] == _ 
   X Y S Z P = 0 0 0 、[]、[(I J )] 一方、P B = N = P pop ()if not Q [ n ]!= _ or n in z ):
     X + = a ; Y + =
   
     b ; z + = [ n ]; p + = [(a b - 1 )、(a + 1 b )、(a b + 1 )、(a - 1 b )]; S + = 1 
   、R = 最大([ 数学関数hypot X / S - X Y / S - Y 用のX Y in z ]); C = { 1 S - (1.4 * R )** 2 )、2 S - R * R / 3 )、3 S - 数学PI * のR *のR )、4 s - 2.5 * r * r )} for p in z
   
    Q [ P ] = C キー= C 得る
I putpalette ([ 0 0 0 _ ] * 3 + [ _ _ 0 ])
I 表示()

1

C#1086バイト

ここでもC#バージョンがないので、記録のための別のフラッドフィルソリューションです。Quincunxのように、私は自分がそれができることを証明したかったのです。Javaでの彼のアプローチにはそれほど違いはありません。

  • StackOverflowsを実行し続けたため、このソリューションでは再帰(スタック)は使用されません。
  • borderpixelsの検出は、次の4つのピクセルを見ると簡単になります。それらのいずれかが黒の場合、現在のピクセルはborder pixelです。

すべての画像形式を受け入れます。

  • パラメーター1 = InputPath
  • パラメーター2 = OutputPath

おそらく、すべての静的なものを削除してProgramのインスタンスを作成することで、いくつかの文字を削除できます。

読み取り可能なバージョン:

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

ゴルフ:

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();}}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.