Calcular el tamaño de la luna

19

El tamaño del misterio de la luna

Estoy seguro de que has oído que la luna cambia de tamaño. Cuando estás enamorado y tienes suerte, la luna tiene casi el doble de tamaño en comparación con las situaciones normales. Algunas personas dicen que la razón es la atmósfera que actúa como lente. Otros piensan que es solo una cuestión de comparación con otros objetos como árboles cercanos. Cualquier explicación que leas, es bastante subjetiva.

El tamaño de la ciencia lunar

Ok, somos programadores, ¿no? Confiamos en los hechos, ¿verdad? Así que aquí está el experimento:

  1. Tome una buena cámara que admita el tiempo de ajuste y la apertura manualmente.
  2. Configure su cámara al máximo nivel de zoom.
  3. Salga, tome algunas fotografías de la luna para detectar la mejor configuración para que la luna sea nítida y la iluminación esté bien.
  4. Recuerda la configuración
  5. Tome fotos de la luna con esos ajustes cada vez que piense que la luna es grande o pequeña.
  6. Calcular el tamaño de la luna en píxeles

La cámara no mentirá, ¿verdad? Al contar los píxeles brillantes, podemos medir efectivamente el tamaño de la luna, al menos en píxeles.

Si el tamaño es el mismo en todas las fotos, entonces es un error en nuestro cerebro. Si el tamaño difiere, entonces hay espacio para la especulación.

  • la luna realmente crece (pero ¿qué come?)
  • hay un efecto de lente atmosférico
  • la luna tiene una curva elíptica y a veces está más cerca, a veces más lejos de la tierra
  • ...

Pero lo dejaré abierto hasta que se complete su tarea. Por supuesto, desea saber de antemano si su software puede calcular el tamaño de la luna con precisión.

La tarea

Dadas algunas imágenes optimizadas de la luna, calcule el tamaño de la luna. La optimización es: los píxeles son blancos o negros. Nada en el medio. Sin antialiasing. Eso lo hace fácil, ¿no?

La advertencia: la luna no siempre está llena, ya sabes ... ¡puede ser una hoz! Pero incluso en forma de hoz, el tamaño de la luna es más grande. Así que calcularás el tamaño completo, por favor.

  • Su programa toma un PNG como entrada, por ejemplo, como argumento de línea de comando de nombre de archivo, canalizado en stdino como un objeto de mapa de bits (de una biblioteca de marco estándar) si escribe una función en lugar de un programa.
  • Su programa funciona con cualquier tamaño de mapa de bits de entrada razonable, no necesariamente cuadrado. Se garantiza un ancho mínimo y una altura de 150 píxeles.
  • La luna llena cubre al menos el 25% de la imagen.
  • Su programa genera el tamaño calculado de la luna en píxeles como si fuera una luna llena.
  • Asumimos que la luna es una esfera perfecta.
  • El tamaño exacto siempre es un número entero, pero puede generar un número decimal si su cálculo lo devuelve.
  • La precisión debe estar entre 98% y 102%. (Eso es más una conjetura que algo que podría garantizar que se pueda lograr. Si cree que es demasiado difícil de alcanzar, deje un comentario).

Actualización :

  • El centro de la luna no está necesariamente en el medio de la imagen.
  • El área visible mínima es el 5% de la luna o el 1,25% del número total de píxeles.
  • La imagen se toma de manera que la luna entera se ajuste a la imagen, es decir, el número total de píxeles es un límite superior para el tamaño de la luna.
  • La luna no se recortará / recortará.

Las muestras

Puede generar sus propias muestras utilizando el archivo de mezcla si lo desea. He creado las siguientes imágenes para ti. Puede contar píxeles en un archivo PNG con WhitePixelCounter.exe (necesita .NET) para verificar si la imagen contiene solo píxeles en blanco y negro y cuántos de ellos.

Las siguientes imágenes de 256x256 píxeles difieren en la cantidad de píxeles blancos, pero todas deben dar como resultado un tamaño de luna calculado de 16416 píxeles.

Luna llena Luna Luna Luna Luna Luna

Y estas imágenes de 177x177 píxeles deberían devolver 10241 píxeles. Las imágenes son básicamente las mismas, pero esta vez se utilizó una cámara con una distancia focal diferente.

Luna Luna Luna Luna Luna Luna

Muestras no cuadradas y no centradas con un resultado de 9988:

Luna en un marco no cuadrado Luna en un marco no cuadrado Luna en un marco no cuadrado Luna en un marco no cuadrado Luna en un marco no cuadrado

Oh, no tengo una implementación de referencia por ahora e incluso no sé si puedo implementar algo. Pero en mi cerebro hay una fuerte creencia que me dice que debe ser matemáticamente solucionable.

Las normas

Este es el código de golf. Se acepta el código más corto el 30/03/2015.

Thomas Weller
fuente
99
En todos los ejemplos, el centro de la luna parece estar centrado dentro de la imagen. ¿Podemos suponer que la luna siempre estará centrada?
Digital Trauma
1
su precisión de +/- 2% en el área corresponde a +/- 1% en el diámetro: ejemplo r = 100 píxeles, área = 10000 * pi; r = 101 píxeles, área = 10201 * pi. Su imagen más pequeña tiene r = 72, por lo tanto d = 144 por lo que debe simplemente ser posible. Sin embargo, para las imágenes debajo de d = 100, creo que la precisión no se pudo cumplir.
Level River St
@ Digital Trauma: el centro no necesita estar en el medio.
Thomas Weller
@ MartinBüttner: el porcentaje mínimo visible es el 5% de la luna o el 1,25% de la imagen.
Thomas Weller
@ MartinBüttner: ok, actualicé la pregunta, actualicé el archivo de mezcla para producir imágenes no cuadradas y no centradas de forma predeterminada. Puede descargar todas las imágenes aquí (* .png.zip) . Contador de píxeles actualizado también: genera más información y comprueba la regla del 1,25%.
Thomas Weller

Respuestas:

10

Mathematica 126119109 bytes

Mathematica puede medir el alargamiento de un componente en una imagen. Una luna llena, siendo perfectamente simétrica, tiene un alargamiento de 0, en una escala de 0 a 1.

Una luna decreciente se alarga cada vez más, hasta un máximo de aproximadamente 0,8.

0.998 -0.788 x-0.578 x^2 fue el modelo empíricamente determinado (basado en las fotos grandes) para `predecir la plenitud de la luna (por área), dado su alargamiento.

Ajusté el modelo para 1- 0.788 x -0.578 x^2que con exactamente elongación cero (luna llena) el modelo devuelva 1 para el factor de escala de píxeles. Ahorra 4 bytes y aún se mantiene dentro de los límites de precisión.

Este modelo se utiliza para imágenes de cualquier tamaño. La imagen de la luna no necesita estar centrada. Tampoco necesita cubrir una proporción fija de la foto.

Aquí están los puntos de datos (alargamiento, displaysMoonPixels / fullMoonPixels) para las imágenes grandes y el modelo parabólico que se generó para ajustarse a los datos. Los modelos lineales se ajustan bien, pero el modelo cuadrático está totalmente activado, dentro de los límites (ver más abajo).

Aquí los datos son de las imágenes grandes. Así es el modelo

grandes medias lunas


A continuación, los datos (los puntos rojos) son de las imágenes pequeñas. El modelo (la curva azul) es el generado por las imágenes grandes, el mismo que se muestra arriba.

La media luna más pequeña tiene un 7,5% del área de luna llena. (La media luna más pequeña entre las fotos grandes es el 19% de la luna llena.) Si el modelo cuadrático se hubiera basado en las fotos pequeñas, el ajuste a continuación sería mejor, solo porque acomoda la media luna pequeña. Un modelo robusto, que se mantendría en pie en una amplia gama de condiciones, incluidas las medias lunas muy pequeñas, estaría mejor hecho de una mayor variedad de imágenes.

La cercanía de ajuste muestra que el modelo no estaba codificado para las imágenes dadas. Podemos estar bastante seguros de que el alargamiento de una luna es independiente del tamaño de la foto, como cabría esperar.

pequeñas medias lunas

ftoma la imagen, icomo entrada y salida del tamaño predicho de la luna llena, en píxeles. Funciona para disparos descentrados.

Como muestran los datos a continuación, todos los casos de prueba excepto uno. Las lunas se arreglaron de lleno a más disminuido.

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

Más de un componente de imagen puede aparecer en una foto. Incluso un solo píxel separado de los demás se considerará un componente distinto. Por esta razón, es necesario buscar "todos" los componentes, para encontrar el que tenga la mayor cantidad de píxeles. (Una de las fotos pequeñas tiene más de un componente de imagen).

Cuadros grandes

Las predicciones del tamaño de la luna hechas a partir de las fotos grandes fueron uniformemente precisas.

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

{"tamaños predichos de luna llena", {16422., 16270.9, 16420.6, 16585.5, 16126.5, 16151.6}}

{"precisión", {1.00037, 0.991161, 1.00028, 1.01033, 0.982367, 0.983891}}


Fotos pequeñas

Las predicciones del tamaño de la luna hechas a partir de las fotos pequeñas fueron uniformes, con una gran excepción, la imagen final. Sospecho que el problema se debe al hecho de que la media luna es muy estrecha.

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

{"tamaños predichos de luna llena", {10247.3, 10161., 10265.6, 10391., 10058.9, 7045.91}}
{"precisión", {1.00061, 0.992192, 1.0024, 1.01465, 0.982221, 0.68801}}

DavidC
fuente
Parece que algún día debería aprender Mathematica. ¿Cuánto tiempo te llevó resolverlo sin jugar al golf?
Thomas Weller
1
@Thomas W Me llevó 2-3 horas experimentar con varios tipos de funciones de procesamiento de imágenes y otros modelos (lineales) hasta que obtuve el gráfico que ves publicado. La codificación no fue muy difícil. Y casi no hay golf aparte de unir funciones separadas en una sola función.
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
Por razones desconocidas, la #2&@@@sugerencia no funciona
DavidC
Huh, lo investigaré más tarde. Otra forma de acortar cesc=Max@ComponentMeasurements[##][[All,2]]&
Martin Ender
5

J, 227207 bytes (error máximo 1.9%)

Mi idea principal es que si podemos encontrar 3 puntos en el contorno de la luna que también están en el contorno de la luna llena, podemos calcular el círculo de estos puntos. Esa circunferencia será a luna llena.

Si encontramos dos puntos blancos con una distancia máxima, siempre serán esos puntos, ya que serán una diagonal real en la luna llena o los puntos finales de la media luna. Podemos encontrar el par de puntos con la mayor distancia en cualquier gráfico seleccionando el punto más alejado de cualquier punto de partida dado y luego seleccionando el punto más alejado del seleccionado.

Encontramos un tercer punto con un valor máximo de los productos de las distancias desde los puntos anteriores. Esto siempre estará en el contorno y en el lado exterior de una media luna o el lado más grande de un giboso.

El diámetro del círculo circunferencial se calcula como la longitud de un lado dividido por el seno del ángulo opuesto.

La complejidad temporal de este método es lineal en el tamaño de la imagen de entrada.

Código

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 función espera el nombre de archivo de entrada como una cadena.

(Para una versión (poco) más legible, verifique el historial de revisiones).

Explicación del código

  • p es una lista de coordenadas de píxeles blancos (llamados puntos en el futuro)
  • la función d calcula distancias entre elementos de p y un punto dado
  • La segunda parte de la definición de s crea una lista de 3 puntos:

    • A es el punto más alejado del primer punto de la lista
    • B es el punto más alejado de A
    • C es un punto con un valor máximo de distancia desde A por distancia de B
  • s es la longitud lateral del triángulo ABC

  • la última línea calcula el área del círculo de ABC que es la luna llena

Resultados

El mayor error es 1.9%.

Las imágenes están en el mismo orden que en la pregunta.

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
fuente
+1 por participar y mencionar el enfoque. Lo siento, no especifiqué que el centro no necesita estar en el medio. Accidentalmente, las imágenes de muestra están todas centradas. Es culpa mía.
Thomas Weller
@ThomasW. Temporalmente borré mi respuesta hasta que la corrijo.
randomra
2

Matlab 162156 (no exactamente en el margen de error actual)

En primer lugar: la precisión es inferior al 2% para todas las imágenes menos una en cada una de las dos series, donde es mayor (aproximadamente 5% y 14%). Mi enfoque fue encontrar los dos píxeles de la luna que están más alejados el uno del otro, y luego usar esto como una estimación del diámetro.

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

Estos son los resultados de precisión (desviación relativa 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
falla
fuente
1

C # - 617

Esta solución no funciona para todas las imágenes, porque en una de las imágenes, la pendiente (m) se convierte en infinito.

El principio fue mencionado antes:

  1. Encuentra dos puntos con distancia máxima (rojo)
  2. Imagina una línea entre ellos (rojo)
  3. Imagine una línea con ángulo rectangular en el medio (verde)
  4. Encuentra puntos blancos en la línea verde
  5. Use el que tenga la máxima distancia de otros puntos (verde)
  6. Calcular el área de un círculo a partir de tres puntos.

Explicación

El caso problemático es este, donde la pendiente es infinita. Es posible solucionarlo girando la imagen 90 ° o en código, bucle sobre el yeje en lugar de x.

Luna problemática

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 precisión mínima es

  • + 1,89% para las imágenes de 256 píxeles
  • -0.55% para las imágenes de 177 píxeles
  • -1,66% para las imágenes no cuadradas
Thomas Weller
fuente