Calculez la taille de la lune

19

La taille du mystère lunaire

Je suis sûr que vous avez entendu que la lune change de taille. Lorsque vous êtes amoureux et que vous avez de la chance, la lune a presque deux fois sa taille par rapport aux situations normales. Certaines personnes disent que la raison en est l'atmosphère qui agit comme une lentille. D'autres pensent que ce n'est qu'une question de comparaison avec d'autres objets tels que les arbres à proximité. Quelle que soit l'explication que vous lisez, c'est assez subjectif.

La taille de la science de la lune

Ok, nous sommes programmeurs, n'est-ce pas? Nous nous appuyons sur des faits, non? Voici donc l'expérience:

  1. Prenez un bel appareil photo qui prend en charge le réglage de l'heure et de l'ouverture manuellement.
  2. Réglez votre appareil photo au niveau de zoom maximum.
  3. Sortez, prenez quelques photos de la lune afin de détecter les meilleurs réglages pour que la lune soit nette et que l'éclairage soit très bien.
  4. Rappelez-vous les paramètres
  5. Prenez des photos de la lune avec ces paramètres chaque fois que vous pensez que la lune est grande ou petite.
  6. Calculez la taille de la lune en pixels

La caméra ne mentira pas, n'est-ce pas? En comptant les pixels lumineux, nous pouvons mesurer efficacement la taille de la lune - au moins en pixels.

Si la taille est la même sur toutes les photos, c'est un bug dans notre cerveau. Si la taille diffère, alors il y a place à la spéculation

  • la lune grandit vraiment (mais que mange-t-elle?)
  • il y a un effet de lentille atmosphérique
  • la lune a une courbe elliptique et est parfois plus proche, parfois plus éloignée de la terre
  • ...

Mais je vais laisser cela ouvert jusqu'à ce que votre tâche soit terminée. Bien sûr, vous voulez savoir à l'avance si votre logiciel peut calculer avec précision la taille de la lune.

La tâche

Compte tenu de quelques images optimisées de la lune, veuillez calculer la taille de la lune. L'optimisation est la suivante: les pixels sont noirs ou blancs. Rien entre les deux. Pas d'anticrénelage. C'est facile, non?

La mise en garde: la lune n'est pas toujours pleine, vous savez ... ça peut être une faucille! Mais même en forme de faucille, la taille de la lune est plus grande. Vous allez donc calculer la taille réelle, s'il vous plaît.

  • Votre programme prend un PNG en entrée, par exemple comme argument de ligne de commande de nom de fichier, canalisé dans stdinou en tant qu'objet Bitmap (d'une bibliothèque de framework standard) si vous écrivez une fonction au lieu d'un programme.
  • Votre programme fonctionne avec n'importe quelle taille de bitmap d'entrée raisonnable, pas nécessairement carrée. La largeur et la hauteur minimales de 150 pixels sont garanties.
  • La pleine lune couvre au moins 25% de l'image.
  • Votre programme affiche la taille calculée de la lune en pixels comme s'il s'agissait d'une pleine lune.
  • Nous supposons que la lune est une sphère parfaite.
  • La taille exacte est toujours un nombre entier, mais vous pouvez sortir un nombre décimal si votre calcul le renvoie.
  • La précision doit être comprise entre 98% et 102%. (C'est plutôt une supposition que quelque chose que je pourrais garantir. Si vous pensez que c'est trop difficile à atteindre, veuillez laisser un commentaire.)

Mise à jour :

  • Le centre de la lune n'est pas nécessairement au milieu de l'image.
  • La zone visible minimale est de 5% de la lune ou 1,25% du nombre total de pixels.
  • La photo est prise de manière à ce que la lune entière s'adapte à l'image, c'est-à-dire que le nombre total de pixels est une limite supérieure pour la taille de la lune.
  • La lune ne sera pas recadrée / coupée.

Les échantillons

Vous pouvez générer vos propres échantillons en utilisant le fichier de mélange si vous le souhaitez. J'ai créé les images suivantes pour vous. Vous pouvez compter les pixels d'un fichier PNG à l'aide de WhitePixelCounter.exe (nécessite .NET) pour vérifier si l'image ne contient que des pixels noir et blanc et combien d'entre eux.

Les images 256x256 pixels suivantes diffèrent par la quantité de pixels blancs, mais devraient toutes entraîner une taille de lune calculée de 16416 pixels.

Pleine lune Lune Lune Lune Lune Lune

Et ces images de 177x177 pixels devraient renvoyer 10241 pixels. Les images sont fondamentalement les mêmes, mais cette fois, un appareil photo avec une distance focale différente a été utilisé.

Lune Lune Lune Lune Lune Lune

Échantillons non carrés et non centrés avec un résultat de 9988:

Lune dans un cadre non carré Lune dans un cadre non carré Lune dans un cadre non carré Lune dans un cadre non carré Lune dans un cadre non carré

Oh, je n'ai pas d'implémentation de référence pour l'instant et je ne sais même pas si je suis capable d'implémenter quelque chose. Mais dans mon cerveau, il y a une forte croyance qui me dit qu'elle doit être mathématiquement soluble.

Les règles

C'est Code Golf. Le code le plus court du 30/03/2015 est accepté.

Thomas Weller
la source
9
Dans tous les exemples, le centre de la lune semble être centré dans l'image. Pouvons-nous supposer que la lune sera toujours centrée?
Digital Trauma
1
votre précision de +/- 2% sur la surface correspond à +/- 1% sur le diamètre: exemple r = 100 pixels, zone = 10000 * pi; r = 101 pixels, zone = 10201 * pi. Votre image plus petite a r = 72 donc d = 144 donc il devrait juste être possible. Pour les images inférieures à d = 100, je pense cependant que la précision n'a pas pu être atteinte.
Level River St
@DigitalTrauma: le centre n'a pas besoin d'être au milieu.
Thomas Weller
@ MartinBüttner: le pourcentage minimum visible est de 5% de la lune ou 1,25% de l'image.
Thomas Weller
@ MartinBüttner: ok, j'ai mis à jour la question, mis à jour le fichier de fusion pour produire des images non carrées et non centrées par défaut. Vous pouvez télécharger toutes les images ici (* .png.zip) . Compteur de pixels mis à jour également: génère plus d'informations et vérifie la règle de 1,25%.
Thomas Weller

Réponses:

10

Mathematica 126119109 octets

Mathematica peut mesurer l'allongement d'un composant dans une image. Une pleine lune, parfaitement symétrique, a un allongement de 0, sur une échelle de 0 à 1.

Une lune décroissante s'allonge de plus en plus, jusqu'à un maximum d'environ 0,8.

0.998 -0.788 x-0.578 x^2 était le modèle déterminé empiriquement (basé sur les grandes photos) pour `prédire la plénitude de la lune (par zone), compte tenu de son allongement.

J'ai ajusté le modèle pour 1- 0.788 x -0.578 x^2que, avec un allongement exactement nul (pleine lune), le modèle renvoie 1 pour le facteur d'échelle de pixels. Il enregistre 4 octets et reste dans les limites de précision.

Ce modèle est utilisé pour toutes les images de taille. L'image de la lune n'a pas besoin d'être centrée. Il n'a pas non plus besoin de couvrir une proportion fixe de la photo.

Voici les points de données (allongement, affichéMoonPixels / fullMoonPixels) pour les grandes images et le modèle parabolique qui a été généré pour s'adapter aux données. Les modèles linéaires conviennent bien, mais le modèle quadratique est mort, dans certaines limites (voir ci-dessous).

Ici, les données proviennent des grandes images. Le modèle aussi

gros croissants


Ci-dessous, les données (les points rouges) proviennent des petites images. Le modèle (la courbe bleue) est celui généré par les grandes images, le même que celui affiché ci-dessus.

Le plus petit croissant a 7,5% de l'aire d'une pleine lune. (Le plus petit croissant parmi les grandes photos est de 19% d'une pleine lune.) Si le modèle quadratique avait été basé sur les petites photos, l'ajustement ci-dessous serait meilleur, uniquement parce qu'il accueillait le petit croissant. Un modèle robuste, qui résisterait dans un large éventail de conditions, y compris de très petits croissants, serait mieux fabriqué à partir d'une plus grande variété d'images.

La proximité de l'ajustement montre que le modèle n'était pas codé en dur pour les images données. Nous pouvons être assez certains que l'allongement d'une lune est indépendant de la taille de la photo, comme on pourrait s'y attendre.

petits croissants

fprend l'image, ien entrée et sort la taille prévue de la pleine lune, en pixels. Cela fonctionne pour les prises de vue décentrées.

Comme le montrent les données ci-dessous, il s'agit de tous les cas de test sauf un. Les lunes étaient disposées du plus complet au plus diminué.

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

Plusieurs composants d'image peuvent apparaître sur une photo. Même un seul pixel séparé des autres sera considéré comme un composant distinct. Pour cette raison, il est nécessaire de rechercher "tous" les composants, pour trouver celui qui a le plus grand nombre de pixels. (L'une des petites photos comporte plusieurs composants d'image.)

Grandes images

Les prédictions de la taille de la lune faites à partir des grandes photos étaient uniformément précises.

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

{"tailles prévues de la pleine lune", {16422., 16270.9, 16420.6, 16585.5, 16126.5, 16151.6}}

{"précision", {1.00037, 0.991161, 1.00028, 1.01033, 0.982367, 0.983891}}


Petites images

Les prédictions de la taille de la lune à partir des petites photos étaient uniformes, à une grande exception près, l'image finale. Je soupçonne que le problème vient du fait que le croissant est très étroit.

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

{"tailles prévues de la pleine lune", {10247.3, 10161., 10265.6, 10391., 10058.9, 7045.91}}
{"précision", {1.00061, 0.992192, 1.0024, 1.01465, 0.982221, 0.68801}}

DavidC
la source
On dirait que je devrais apprendre Mathematica un jour. Combien de temps vous a-t-il fallu pour le résoudre sans jouer au golf?
Thomas Weller
1
@Thomas W Il a fallu 2-3 heures pour expérimenter différentes sortes de fonctionnalités de traitement d'image et d'autres modèles (linéaires) jusqu'à ce que j'obtienne le graphique que vous voyez publié. Le codage n'a pas été très difficile. Et il n'y a presque pas de golf autre que l'union de fonctions séparées en une seule fonction.
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
Pour des raisons inconnues, la #2&@@@suggestion ne fonctionne pas
DavidC
Huh, je verrai ça plus tard. Une autre façon de raccourcir cestc=Max@ComponentMeasurements[##][[All,2]]&
Martin Ender
5

J, 227207 octets (erreur maximale 1,9%)

Mon idée principale est que si nous pouvons trouver 3 points sur le contour de la lune qui se trouvent également sur le contour de la pleine lune, nous pouvons calculer le cercle circonscrit de ces points. Ce cercle sera à la pleine lune.

Si nous trouvons deux points blancs avec une distance maximale, ce seront toujours des points tels qu'ils seront soit une vraie diagonale à la pleine lune, soit les extrémités du croissant. Nous pouvons trouver la paire de points avec la plus grande distance dans n'importe quel graphique en sélectionnant le point le plus éloigné d'un point de départ donné, puis en sélectionnant le point le plus éloigné du point sélectionné.

On retrouve un troisième point avec une valeur maximale des produits des distances aux points précédents. Ce sera toujours sur le contour et sur le côté extérieur d'un croissant ou le plus grand côté d'un gibbeux.

Le diamètre du cercle circonscrit est calculé comme la longueur d'un côté divisée par le sinus de l'angle opposé.

La complexité temporelle de cette méthode est linéaire dans la taille de l'image d'entrée.

Code

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
)

La fonction attend le nom de fichier d'entrée sous forme de chaîne.

(Pour une version (un peu) plus lisible, consultez l'historique des révisions.)

Explication du code

  • p est une liste de coordonnées de pixels blancs (appelés points dans le futur)
  • la fonction d calcule les distances entre les éléments de p et un point donné
  • la deuxième partie de la définition de s crée une liste en 3 points:

    • A est le point le plus éloigné du premier point de la liste
    • B est le point le plus éloigné de A
    • C est un point avec une valeur maximale de distance de forme A fois la distance de B
  • s est la longueur des côtés du triangle ABC

  • la dernière ligne calcule l'aire du cercle circonscrit de ABC qui est la pleine lune

Résultats

La plus grande erreur est de 1,9%.

Les images sont dans le même ordre que dans la question.

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
la source
+1 pour avoir participé et mentionné l'approche. Je suis désolé de ne pas avoir précisé que le centre n'a pas besoin d'être au milieu. Accidentellement, les échantillons d'images sont tous centrés. C'est de ma faute.
Thomas Weller
@ThomasW. Supprimé temporairement ma réponse jusqu'à ce que je la corrige.
randomra
2

Matlab 162 156 (pas tout à fait dans la marge d'erreur actuelle)

Tout d'abord: la précision est inférieure à 2% pour toutes les images sauf une dans chacune des deux séries, où elle est supérieure (environ 5% et 14%). Mon approche consistait à trouver les deux pixels de la lune les plus éloignés l'un de l'autre, puis à les utiliser comme estimation du diamètre.

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

Ce sont les résultats de précision (écart 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
flawr
la source
1

C # - 617

Cette solution ne fonctionne pas pour toutes les images, car sur l'une des images, la pente (m) devient infinie.

Le principe a été mentionné précédemment:

  1. Trouver deux points avec une distance maximale (rouge)
  2. Imaginez une ligne entre eux (rouge)
  3. Imaginez une ligne avec un angle rectangulaire au milieu (vert)
  4. Trouvez des points blancs sur la ligne verte
  5. Utilisez celui avec la distance maximale des autres points (vert)
  6. Calculer l'aire d'un cercle à partir de trois points

Explication

Le cas problématique est celui-ci, où la pente est infinie. Il est possible de contourner ce problème en faisant pivoter l'image de 90 ° ou en code, en boucle sur l' yaxe au lieu de x.

Lune problématique

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

La précision minimale est

  • + 1,89% pour les images 256 pixels
  • -0,55% pour les images à 177 pixels
  • -1,66% pour les images non carrées
Thomas Weller
la source