月の大きさを計算する


19

月の謎の大きさ

月のサイズが変わることを聞いたことがあると思います。あなたが恋をしていて幸運なとき、月は通常の状況に比べてほぼ2倍の大きさです。一部の人々は、理由はレンズとして機能する雰囲気だと言います。他の人は、近くの木など他のオブジェクトとの比較の問題にすぎないと考えています。どのような説明を読んでも、それは非常に主観的なものです。

月の科学の大きさ

プログラマーですよね?事実に頼っていますよね?だからここに実験があります:

  1. 時間と絞りの手動設定をサポートする素敵なカメラを用意してください。
  2. カメラを最大ズームレベルに設定します。
  3. 外に出て、月の写真を撮って、最適な設定を検出して、月がシャープになり、照明がちょうど良いようにします。
  4. 設定を覚えておいてください
  5. 月が大きいか小さいと思うたびに、これらの設定で月の写真を撮ります。
  6. 月のサイズをピクセルで計算する

カメラは嘘をつきませんよね?明るいピクセルを数えることで、月の大きさを少なくともピクセル単位で効果的に測定できます。

サイズがすべての写真で同じ場合、それは私たちの脳のバグです。サイズが異なる場合、推測の余地があります

  • 月は本当に成長します(しかし、それは何を食べますか?)
  • 大気のレンズ効果があります
  • 月は楕円曲線を持ち、時には近く、時には地球から遠く離れています
  • ...

ただし、タスクが完了するまで開いたままにします。もちろん、ソフトウェアが月のサイズを正確に計算できるかどうかを事前に知りたいと思うでしょう。

タスク

月の最適化された写真をいくつか与えて、月のサイズを計算してください。最適化は次のとおりです。ピクセルは黒または白です。間に何もない。アンチエイリアスなし。これで簡単になりますよね?

警告:月はいつも満杯ではありません、あなたは知っています...それは鎌でありえます!しかし、鎌の形であっても、月のサイズは大きくなります。したがって、フルサイズを計算してください。

  • プログラムは、PNGを入力として受け取ります。たとえばstdin、プログラムの代わりに関数を記述する場合、ファイル名のコマンドライン引数として、または(標準フレームワークライブラリの)Bitmapオブジェクトとしてパイプされます。
  • プログラムは、適切な入力ビットマップサイズで動作しますが、必ずしも正方形ではありません。150ピクセルの最小幅と高さが保証されています。
  • 満月は写真の少なくとも25%を覆います。
  • プログラムは、満月のように計算された月のサイズをピクセル単位で出力します。
  • 月は完全な球体であると仮定します。
  • 正確なサイズは常に整数ですが、計算で返される場合は10進数を出力できます。
  • 精度は98%から102%の間でなければなりません。(それは私が達成できると保証できるものよりもむしろ推測です。到達するのが難しすぎると思われる場合は、コメントを残してください。)

更新

  • 月の中心は必ずしも写真の中央にあるとは限りません。
  • 最小の可視領域は月の5%またはピクセルの総数の1.25%です。
  • 写真は、月全体が画像に合うように撮影されます。つまり、ピクセルの総数は月のサイズの上限です。
  • 月は切り取られません。

サンプル

必要に応じて、ブレンドファイルを使用して独自のサンプルを生成できます。次の写真を作成しました。WhitePixelCounter.exe(.NETが必要)を使用してPNGファイル内のピクセルをカウントし、イメージに黒と白のピクセルのみが含まれているかどうか、およびそれらの数を確認できます。

次の256x256ピクセルの画像は白いピクセルの量が異なりますが、計算された月のサイズは16416ピクセルになります。

満月 月 月 月 月 月

そして、これらの177x177ピクセルの画像は10241ピクセルを返すはずです。画像は基本的に同じですが、今回は焦点距離の異なるカメラが使用されました。

月 月 月 月 月 月

結果が9988の非正方形および非中心サンプル:

非正方形フレームの月 非正方形フレームの月 非正方形フレームの月 非正方形フレームの月 非正方形フレームの月

ああ、私は今のところリファレンス実装を持っていませんし、何かを実装できるかどうかさえ知りません。しかし、私の脳には、数学的に解決可能でなければならないという強い信念があります。

ルール

これはコードゴルフです。2015-03-30の最短コードが受け入れられます。


9
すべての例で、月の中心は写真の中心にあるように見えます。月が常に中心にあると仮定できますか?
デジタル外傷

1
面積の+/- 2%の精度は、直径の+/- 1%に対応します。例r = 100ピクセル、面積= 10000 * pi; r = 101ピクセル、面積= 10201 * pi。それがなければならないので、あなたの小さな画像は、r = 72、したがってD = 144を有しているだけで可能です。ただし、d = 100未満の画像の場合、精度を満たせなかったと思います。
レベル川セント

@DigitalTrauma:センターは中央にある必要はありません。
トーマスウェラー

@MartinBüttner:目に見える最小の割合は月の5%または画像の1,25%です。
トーマスウェラー

@MartinBüttner:わかりました、質問を更新しました。デフォルトでは、正方形ではなく中心のない画像を生成するようにブレンドファイルを更新しました。ここからすべての画像をダウンロードできます(* .png.zip)。ピクセルカウンターも更新されました。さらに情報を出力し、1.25%ルールをチェックします。
トーマスウェラー

回答:


10

Mathematica 126119109バイト

Mathematicaは画像内の成分の伸びを測定できます。完全に対称な満月は、0から1のスケールで0の伸びを持ちます。

減少する月は次第に長くなり、最大で約0.8になります。

0.998 -0.788 x-0.578 x^2 は、その拡大を考慮して、「月の膨満を(面積で)予測する」ための経験的に決定されたモデル(大きな写真に基づく)でした。

モデルを調整しました 1- 0.788 x -0.578 x^2正確にゼロの伸び(満月)でモデルがピクセルスケールファクターに対して1を返すように。4バイトを節約し、精度の制限内にとどまります。

このモデルは、あらゆるサイズの画像に使用されます。月の画像は中央に配置する必要はありません。また、写真の一定の割合をカバーする必要はありません。

ここに、大きな画像とデータに適合するように生成された放物線モデルのデータポイント(伸び、displayedMoonPixels / fullMoonPixels)があります。線形モデルは問題ありませんが、2次モデルは制限内で機能しません(以下を参照)。

ここでは、データは大きな写真からのものです。モデルもそうです

大きな三日月


以下のデータ(赤い点)は小さな写真からのものです。モデル(青い曲線)は、大きな画像で生成されたもので、上記と同じものです。

最も小さい三日月の満月の面積は7.5%です。(大きな写真の中で最小の三日月は満月の19%です。)二次モデルが小さな写真に基づいていた場合、小さな三日月を収容したという理由だけで、下のフィットがより良いでしょう。非常に小さな三日月を含む広範囲の条件下で立ち上がる堅牢なモデルは、より多くの種類の写真から作成する方が良いでしょう。

近似度は、与えられた写真に対してモデルがハードコーディングされていないことを示しています。予想されるように、月の伸びが写真のサイズに依存しないことはかなり確信で​​きます。

小さな三日月

f 画像を撮る、 i入力としてピクセルで満月の予測サイズを出力します。中心から外れたショットでも機能します。

以下のデータが示すように、1つを除くすべてのテストケース。月は完全なものから最も減少したものまで並べられました。

i_~c~t_ := Max@ComponentMeasurements[i, t][[All, 2]];
f@i_ := i~c~"Count"/(1 - 0.788 x - 0.578 x^2 /. x -> i~c~"Elongation")

写真に複数の画像コンポーネントが表示される場合があります。他のピクセルから分離された単一のピクセルでさえ、別個のコンポーネントと見なされます。このため、ピクセル数の多いコンポーネントを見つけるために、「すべての」コンポーネントを検索する必要があります。(小さな写真の1つに複数の画像コンポーネントがあります。)

大きな写真

大きな写真から作られた月の大きさの予測は、均一に正確でした。

{"predicted size of full moon", f[#] & /@ large}
{"accuracy", %[[2]]/16416}

{「満月の予測サイズ」、{16422.、16270.9、16420.6、16585.5、16126.5、16151.6}}

{「精度」、{1.00037、0.991161、1.00028、1.01033、0.982367、0.983891}}


小さな写真

小さな写真から作られた月の大きさの予測は、1つの大きな例外を除いて、最終的な写真で均一でした。この問題は、三日月が非常に狭いという事実に起因していると思われます。

{"predicted sizes of full moon", f[#] & /@ small}
{"accuracy", %[[2]]/10241}

{「満月の予測サイズ」、{10247.3、10161。、10265.6、10391。、10058.9、7045.91}}
{「精度」、{1.00061、0.992192、1.00024、1.01465、0.982221、0.68801}}


いつかMathematicaを学ぶ必要があるようです。ゴルフをせずに解決するのにどれくらいかかりましたか?
トーマスウェラー

1
@Thomas W投稿されたグラフを取得するまで、さまざまな種類の画像処理機能やその他の(線形)モデルを実験するのに2〜3時間かかりました。コーディングはそれほど難しくありませんでした。そして、別々の機能を単一の機能に統合する以外にゴルフはほとんどありません。
DavidC

104: i_~c~t_:=Max[#2&@@@i~ComponentMeasurements~t];f@i_:=i~c~"Count"/(1-0.788x-0.578x^2/.x->i~c~"Elongation")
マーティンエンダー

理由は不明ですが、#2&@@@提案は機能しません
-DavidC

えっと、後で調べます。短縮する別の方法cc=Max@ComponentMeasurements[##][[All,2]]&
マーティンエンダー

5

J、227207バイト(最大エラー1.9%)

私の主なアイデアは、満月の輪郭上にある月の輪郭上に3つの点を見つけることができれば、これらの点の外接円計算できるということです。その外接円は満月になります。

最大距離を持つ2つの白い点が見つかった場合、それらは常に満月の実際の対角線または三日月の終点のいずれかであるような点になります。任意の開始点から最も遠い点を選択してから、選択したものから最も遠い点を選択することにより、グラフ内で最大距離を持つ点のペアを見つけることができます。

前のポイントからの距離の積の最大値を持つ3番目のポイントを見つけます。これは、常に輪郭上、三日月の外側またはギブスの大きい側になります。

外接円の直径は、片側の長さを反対側の角度の洞で割って計算されます。

この方法の時間的な複雑さは、入力画像のサイズに比例します。

コード

f=.3 :0
load'graphics/png'
i=.readpng y
p=.(,i=_1)#|:,"%.0 1|:,"0/&>/<@i."*$i
s=.%:+/|:*:(-1|.]) (([,],:m@(*&d))(m@d))(m=.p{~(i.>./)@])(d=.+/@:*:@((|:p)-])) 0{p
o.*:-:({.s)%0 o.((+/-2*{.)*:s)%2**/}.s
)

この関数は、入力ファイル名を文字列として想定しています。

((少し)より読みやすいバージョンチェックリビジョン履歴。)

コードの説明

  • pは白いピクセル座標のリストです(将来的にポイントと呼ばれます)
  • 関数dは、pの要素と指定された点の間の距離を計算します
  • sの定義の2番目の部分は、3ポイントリストを作成します。

    • Aはリストの最初のポイントから最も遠いポイントです
    • BはAから最も遠い点です
    • Cは、距離フォームAの最大値がBからの距離の点です。
  • sは、三角形ABCの​​辺の長さです

  • 最後の行は、満月であるABCの外接円の面積を計算します

結果

最大のエラーは1.9%です。

画像は質問と同じ順序です。

Output  Accuracy
----------------
  16407 0.999453 NB. Large images
16375.3 0.997523
16223.9 0.988301
16241.5 0.989369
16262.6 0.990654
16322.1 0.994279
10235.3 0.999445 NB. Small images
10235.3 0.999444
10221.2 0.998067
10220.3 0.997978
  10212 0.997169
10229.6  0.99889
9960.42 0.997239 NB. Offset images
9872.22 0.988408
10161.8   1.0174
9874.95 0.988681
 9805.9 0.981768

アプローチへの参加と言及に+1。センターが真ん中にある必要がないことを指定しなかったのが残念です。誤って、サンプル画像はすべて中央に配置されます。それは私のせいだ。
トーマスウェラー

しゅう 修正するまで、回答を一時的に削除しました。
ランダラ

2

Matlab 162 156(現在のエラーマージンではありません)

まず第一に:2つのシリーズのそれぞれで1つを除くすべての画像の精度は2%未満であり、より高い(約5%および14%)。私のアプローチは、互いに最も遠い月の2つのピクセルを見つけ、それを直径の推定値として使用することでした。

a=imread(input(''));                 %read input image
b=a(:,:,1)>0;                        %binarize red channel
s=size(b);                           %get size of the image
[x,y]=meshgrid(1:s(1),1:s(2));       
z=(x+i*y).*b;z=z(z~=0);              %find the coordinates of all white pixels (as a list)
o=ones(size(z(:)))*z(:)';            
disp(max(max(abs(o-o.').^2))*pi/4);  %calculate the maximum of the distance between each possible pair and evaluate area formula

これらは精度の結果です(相対偏差1 - (predicted size / real size)

0.0006 0.0025 0.0169 0.0500 0.0521 0.0113 0.0006 0.0006 0.0026 0.0472 0.1383 0.0131

1

C#-617

このソリューションは、すべての画像で機能するわけではありません。画像の1つで、勾配(m)が無限になるためです。

原理は以前に言及されました:

  1. 最大距離(赤)の2点を見つける
  2. それらの間の線を想像してください(赤)
  3. 中央に長方形の角がある線(緑)を想像してください
  4. 緑の線上の白い点を見つける
  5. 他のポイントからの最大距離を持つものを使用します(緑)
  6. 3点から円の面積を計算する

説明

問題のあるケースは、勾配が無限大であるこのケースです。画像を90°回転させるか、コードで、のy代わりに軸をループすることで回避策をとることができxます。

問題のある月

double A(Bitmap b){var a=new List<P>();for(var y=0;y<b.Height;y++)for(var x=0;x<b.Width;x++)if(b.GetPixel(x,y).R>0)a.Add(new P{x=x,y=y});double c=0.0,d=0.0,e=0.0,f=0.0,g=0.0,n=double.MaxValue;foreach(var h in a)foreach(var i in a){var t=Math.Sqrt(Math.Pow(h.x-i.x,2)+Math.Pow(h.y-i.y,2));if(t>c){d=h.x;f=i.x;e=h.y;g=i.y;c=t;}}c=(f-d)/(e-g);for(int x=0;x<b.Width;x++){int y=(int)(c*x+((e+g)/2-c*(d+f)/2));if(y>=0&&y<b.Height&&b.GetPixel(x,y).R>0){var s=(g-e)/(f-d);var q=(y-g)/(x-f);var j=(s*q*(e-y)+q*(d+f)-s*(f+x))/(2*(q-s));var k=-(j-(d+f)/2)/s+(e+g)/2;var l=(j-d)*(j-d)+(k-e)*(k-e);if(l<n)n=l;}}return Math.PI*n;}

最小精度は

  • 256ピクセルの画像では+ 1,89%
  • 177ピクセル画像の場合-0.55%
  • 非正方形画像の場合は-1.66%
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.