Hitung ukuran bulan

19

Ukuran misteri bulan

Saya yakin Anda pernah mendengar bahwa bulan mengubah ukurannya. Ketika Anda sedang jatuh cinta dan Anda beruntung, ukuran bulan hampir dua kali lipat dibandingkan dengan situasi normal. Sebagian orang mengatakan alasannya adalah suasana yang bertindak sebagai lensa. Yang lain berpikir bahwa itu hanya masalah perbandingan dengan benda lain seperti pohon di dekatnya. Apapun penjelasan yang Anda baca, itu cukup subjektif.

Ukuran ilmu bulan

Ok, kita programmer, bukan? Kami mengandalkan fakta, bukan? Jadi inilah eksperimennya:

  1. Ambil kamera yang bagus yang mendukung pengaturan waktu dan bukaan secara manual.
  2. Setel kamera Anda ke level zoom maksimum.
  3. Pergi keluar, ambil beberapa foto bulan untuk mendeteksi pengaturan terbaik sehingga bulan tajam dan pencahayaan baik-baik saja.
  4. Ingat pengaturannya
  5. Ambil foto bulan dengan pengaturan itu setiap kali Anda berpikir bulan besar atau kecil.
  6. Hitung ukuran bulan dalam piksel

Kamera tidak akan berbohong, bukan? Dengan menghitung piksel cerah kita dapat secara efektif mengukur ukuran bulan - setidaknya dalam piksel.

Jika ukurannya sama di semua foto, maka itu adalah bug di otak kita. Jika ukurannya berbeda, maka ada ruang untuk spekulasi

  • bulan benar-benar tumbuh (tetapi apa yang dimakannya?)
  • ada efek lensa atmosfer
  • bulan memiliki kurva elips dan kadang lebih dekat, kadang jauh dari bumi
  • ...

Tapi saya akan membiarkannya terbuka sampai tugas Anda selesai. Tentu saja Anda ingin tahu sebelumnya jika perangkat lunak Anda dapat menghitung ukuran bulan secara akurat.

Tugas

Diberikan beberapa gambar bulan yang dioptimalkan, harap hitung ukuran bulan. Optimasinya adalah: pikselnya hitam atau putih. Tidak ada di antara keduanya. Tidak ada antialiasing. Itu membuatnya mudah, bukan?

Peringatan: bulan tidak selalu penuh, Anda tahu ... itu bisa menjadi sabit! Tetapi bahkan dalam bentuk sabit, ukuran bulan lebih besar. Jadi, Anda akan menghitung ukuran penuh, silakan.

  • Program Anda mengambil PNG sebagai input, misalnya sebagai argumen baris perintah nama file, disalurkan ke stdinatau sebagai objek Bitmap (dari pustaka kerangka kerja standar) jika Anda menulis fungsi alih-alih program.
  • Program Anda bekerja dengan ukuran bitmap input yang masuk akal, tidak harus kuadrat. Lebar minimum dan tinggi 150 piksel dijamin.
  • Bulan purnama mencakup setidaknya 25% dari gambar.
  • Program Anda menampilkan ukuran bulan yang dihitung dalam piksel seolah-olah bulan purnama.
  • Kami berasumsi bahwa bulan adalah bola yang sempurna.
  • Ukuran pastinya selalu angka integer, tetapi Anda bisa menampilkan angka desimal jika kalkulasi Anda mengembalikannya.
  • Akurasi harus antara 98% dan 102%. (Itu lebih merupakan dugaan daripada sesuatu yang dapat saya jamin untuk dapat dicapai. Jika Anda pikir itu terlalu sulit untuk dijangkau, silakan tinggalkan komentar.)

Perbarui :

  • Pusat bulan tidak harus di tengah-tengah gambar.
  • Daerah minimum yang terlihat adalah 5% dari bulan atau 1,25% dari total jumlah piksel.
  • Gambar diambil sedemikian rupa sehingga seluruh bulan akan sesuai dengan gambar, yaitu jumlah total piksel adalah batas atas untuk ukuran bulan.
  • Bulan tidak akan dipotong / dipotong.

Sampel

Anda dapat membuat sampel sendiri menggunakan file campuran jika diinginkan. Saya telah membuat gambar-gambar berikut untuk Anda. Anda dapat menghitung piksel dalam file PNG menggunakan WhitePixelCounter.exe (perlu .NET) untuk memeriksa apakah gambar tersebut hanya berisi piksel hitam putih saja dan berapa jumlahnya.

Gambar 256x256 piksel berikut berbeda dalam jumlah piksel putih, tetapi semua harus menghasilkan ukuran bulan terhitung 16416 piksel.

Bulan purnama Bulan Bulan Bulan Bulan Bulan

Dan gambar 177x177 piksel ini harus mengembalikan 10241 piksel. Gambar pada dasarnya sama, tetapi kali ini kamera dengan focal length berbeda digunakan.

Bulan Bulan Bulan Bulan Bulan Bulan

Sampel non-square dan non-centered dengan hasil 9988:

Bulan dalam bingkai non-persegi Bulan dalam bingkai non-persegi Bulan dalam bingkai non-persegi Bulan dalam bingkai non-persegi Bulan dalam bingkai non-persegi

Oh, saya tidak memiliki implementasi referensi untuk saat ini dan saya bahkan tidak tahu apakah saya bisa mengimplementasikan sesuatu. Tetapi di otak saya ada keyakinan kuat yang mengatakan bahwa itu harus dipecahkan secara matematis.

Aturan

Ini Golf Code. Kode terpendek pada 2015-03-30 diterima.

Thomas Weller
sumber
9
Dalam semua contoh, pusat bulan tampak berpusat di dalam gambar. Bisakah kita menganggap bulan akan selalu terpusat?
Digital Trauma
1
akurasi Anda +/- 2% pada area sesuai dengan +/- 1 pada diameter: contoh r = 100 piksel, area = 10000 * pi; r = 101 piksel, area = 10201 * pi. Gambar Anda yang lebih kecil memiliki r = 72 karena itu d = 144 jadi seharusnya hanya mungkin. Namun untuk gambar di bawah d = 100 saya rasa akurasinya tidak dapat dipenuhi.
Level River St
@ DigitalTrauma: pusat tidak harus di tengah.
Thomas Weller
@ MartinBüttner: persentase minimum yang terlihat adalah 5% dari bulan atau 1,25% dari gambar.
Thomas Weller
@ MartinBüttner: ok, saya telah memperbarui pertanyaan, memperbarui file campuran untuk menghasilkan gambar yang tidak terpusat dan tidak terpusat secara default. Anda dapat mengunduh semua gambar di sini (* .png.zip) . Penghitung piksel yang diperbarui juga: menampilkan beberapa informasi lebih lanjut dan memeriksa aturan 1,25%.
Thomas Weller

Jawaban:

10

Mathematica 126 119 109 byte

Mathematica dapat mengukur perpanjangan komponen dalam suatu gambar. Bulan purnama, menjadi simetris sempurna, memiliki perpanjangan 0, pada skala 0 hingga 1.

Bulan yang semakin berkurang semakin memanjang, hingga maksimum sekitar 0,8.

0.998 -0.788 x-0.578 x^2 adalah model yang ditentukan secara empiris (berdasarkan foto-foto besar) untuk `memprediksi kepenuhan bulan (berdasarkan area), mengingat pemanjangannya.

Saya menyesuaikan model 1- 0.788 x -0.578 x^2sehingga dengan pemanjangan nol (bulan purnama) model akan mengembalikan 1 untuk faktor skala piksel. Menghemat 4 byte dan masih tetap dalam batas akurasi.

Model ini digunakan untuk berbagai ukuran gambar. Gambar bulan tidak perlu dipusatkan. Itu juga tidak perlu mencakup proporsi foto yang tetap.

Berikut adalah titik data (perpanjangan, ditampilkanMoonPixels / fullMoonPixels) untuk gambar besar dan model parabola yang dihasilkan agar sesuai dengan data. Model linier pas ok, tetapi model kuadrat mati, dalam batas (lihat di bawah).

Di sini datanya dari gambar-gambar besar. Begitu juga modelnya

sabit besar


Di bawah ini, data (titik merah) dari gambar kecil. Model (kurva biru) adalah yang dihasilkan oleh gambar-gambar besar, sama seperti yang ditampilkan di atas.

Bulan sabit terkecil memiliki 7,5% luas bulan purnama. (Bulan sabit terkecil di antara foto-foto besar adalah 19% dari bulan purnama.) Jika model kuadratik didasarkan pada foto-foto kecil, pas di bawah akan lebih baik, hanya karena menampung bulan sabit kecil. Model yang kuat, yang akan bertahan dalam berbagai kondisi, termasuk bulan sabit yang sangat kecil, akan lebih baik dibuat dari variasi gambar yang lebih besar.

Kedekatan cocok menunjukkan bahwa model itu tidak memiliki kode untuk gambar yang diberikan. Kita dapat cukup yakin bahwa perpanjangan bulan tidak tergantung pada ukuran foto, seperti yang diharapkan.

sabit kecil

fmengambil gambar,, isebagai input dan output ukuran bulan purnama, dalam piksel. Ini berfungsi untuk pemotretan di luar tengah.

Seperti yang ditunjukkan oleh data di bawah ini, semua kasus uji kecuali satu. Bulan-bulan itu diatur dari penuh hingga paling berkurang.

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

Lebih dari satu komponen gambar dapat muncul di foto. Bahkan satu piksel terpisah dari yang lain akan dianggap sebagai komponen yang berbeda. Untuk alasan ini, perlu mencari komponen "semua", untuk menemukan komponen yang memiliki jumlah piksel lebih besar. (Salah satu foto kecil memiliki lebih dari satu komponen gambar.)

Gambar besar

Prediksi ukuran bulan yang dibuat dari foto-foto besar itu akurat secara seragam.

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

{"ukuran prediksi bulan purnama", {16422., 16270.9, 16420.6, 16585.5, 16126.5, 16151.6}}

{"akurasi", {1.00037, 0.991161, 1.00028, 1.01033, 0.982367, 0.983891}}


Gambar kecil

Prediksi ukuran bulan yang dibuat dari foto-foto kecil itu seragam, dengan satu pengecualian besar, gambar akhir. Saya menduga masalah ini berasal dari kenyataan bahwa bulan sabit sangat sempit.

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

{"ukuran prediksi bulan purnama", {10247.3, 10161., 10265.6, 10391., 10058.9, 7045.91}}
{"akurasi", {1.00061, 0.992192, 1.0024, 1.01465, 0.982221, 0.68801}}

DavidC
sumber
Sepertinya saya harus belajar Mathematica suatu hari. Berapa lama yang Anda butuhkan untuk menyelesaikannya tanpa bermain golf?
Thomas Weller
1
@ Thomas W Membutuhkan waktu 2-3 jam bereksperimen dengan berbagai macam fitur pemrosesan gambar dan model (linier) lainnya sampai saya memperoleh grafik yang Anda lihat diposting. Pengkodean itu tidak terlalu sulit. Dan hampir tidak ada golf selain menyatukan fungsi yang terpisah menjadi satu fungsi.
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")
Martin Ender
Untuk alasan yang tidak diketahui, #2&@@@saran tersebut tidak berfungsi
DavidC
Huh, aku akan memeriksanya nanti. Cara lain untuk mempersingkat cadalahc=Max@ComponentMeasurements[##][[All,2]]&
Martin Ender
5

J, 227 207 byte (kesalahan maksimal 1,9%)

Gagasan utama saya adalah bahwa jika kita dapat menemukan 3 titik pada kontur bulan yang berada pada kontur bulan purnama juga kita dapat menghitung lingkaran dari titik-titik ini. Lingkaran itu akan menuju bulan purnama.

Jika kita menemukan dua titik putih dengan jarak maksimal, itu akan selalu menjadi titik-titik karena keduanya akan berupa diagonal nyata di bulan purnama atau titik akhir bulan sabit. Kita dapat menemukan pasangan titik dengan jarak terbesar dalam grafik apa pun dengan memilih titik terjauh dari titik awal yang diberikan dan kemudian memilih titik terjauh dari titik yang dipilih.

Kami menemukan titik ketiga dengan nilai maksimal dari produk jarak dari titik sebelumnya. Ini akan selalu berada di kontur dan di sisi luar bulan sabit atau sisi yang lebih besar dari siamang.

Diameter sirkumulus dihitung sebagai panjang satu sisi dibagi dengan sinus dari sudut yang berlawanan.

Kompleksitas waktu dari metode ini linier dalam ukuran gambar input.

Kode

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
)

Fungsi mengharapkan nama file input sebagai string.

(Untuk versi revisi riwayat revisi yang lebih mudah dibaca.)

Penjelasan kode

  • p adalah daftar koordinat piksel putih (disebut titik di masa depan)
  • fungsi d menghitung jarak antara elemen p dan titik tertentu
  • bagian kedua dari definisi s membuat daftar 3 poin:

    • A adalah titik terjauh dari titik pertama dalam daftar
    • B adalah titik terjauh dari A
    • C adalah titik dengan nilai maksimal bentuk jarak A kali jarak dari B
  • s adalah panjang sisi dari segitiga ABC

  • baris terakhir menghitung luas lingkaran ABC yang merupakan bulan purnama

Hasil

Kesalahan terbesar adalah 1,9%.

Gambar berada dalam urutan yang sama seperti dalam pertanyaan.

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
randomra
sumber
+1 untuk berpartisipasi dan menyebutkan pendekatan. Maaf saya tidak menentukan bahwa pusat tidak harus di tengah. Secara tidak sengaja gambar sampel semuanya terpusat. Itu salah saya.
Thomas Weller
@ Thomas. Hapus sementara jawaban saya sampai saya memperbaikinya.
randomra
2

Matlab 162 156 (tidak cukup dalam margin kesalahan saat ini)

Pertama-tama: Akurasi di bawah 2% untuk semua kecuali satu gambar di masing-masing dari dua seri, di mana lebih besar (sekitar 5% dan 14%). Pendekatan saya adalah menemukan dua piksel bulan yang paling jauh satu sama lain, dan kemudian menggunakan ini sebagai perkiraan untuk diameter.

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

Ini adalah hasil akurasi (penyimpangan relatif 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
cacat
sumber
1

C # - 617

Solusi ini tidak berfungsi untuk semua gambar, karena pada salah satu gambar, kemiringan (m) menjadi tak terbatas.

Prinsip itu disebutkan sebelumnya:

  1. Temukan dua titik dengan jarak maksimum (merah)
  2. Bayangkan sebuah garis di antara mereka (merah)
  3. Bayangkan sebuah garis dengan sudut persegi panjang di tengah (hijau)
  4. Temukan titik putih di garis hijau
  5. Gunakan satu dengan jarak maksimum dari titik lain (hijau)
  6. Hitung luas lingkaran dari tiga titik

Penjelasan

Kasus yang bermasalah adalah yang ini, di mana kemiringannya tak terbatas. Dimungkinkan untuk mengatasinya dengan memutar gambar 90 ° atau dalam kode, loop di atas ysumbu bukan x.

Bulan bermasalah

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

Akurasi minimum adalah

  • + 1,89% untuk gambar 256 piksel
  • -0,55% untuk gambar 177 piksel
  • -1,66% untuk gambar non-persegi
Thomas Weller
sumber