Calcular o tamanho da lua

19

O tamanho do mistério da lua

Tenho certeza que você já ouviu falar que a lua muda de tamanho. Quando você está apaixonado e tem sorte, a lua tem quase o dobro do tamanho em comparação com situações normais. Algumas pessoas dizem que o motivo é a atmosfera que age como uma lente. Outros pensam que é apenas uma questão de comparação com outros objetos, como árvores próximas. Seja qual for a explicação que você lê, é bastante subjetiva.

O tamanho da ciência da lua

Ok, somos programadores, não somos? Contamos com fatos, certo? Então, aqui está o experimento:

  1. Pegue uma boa câmera que suporte a hora e a abertura manualmente.
  2. Defina sua câmera para o nível máximo de zoom.
  3. Saia, tire algumas fotografias da lua para detectar as melhores configurações, para que a lua fique nítida e a iluminação esteja ótima.
  4. Lembre-se das configurações
  5. Tire fotos da lua com essas configurações sempre que achar que a lua é grande ou pequena.
  6. Calcular o tamanho da lua em pixels

A câmera não mente, não é? Contando os pixels brilhantes, podemos medir efetivamente o tamanho da lua - pelo menos em pixels.

Se o tamanho é o mesmo em todas as fotos, é um erro no nosso cérebro. Se o tamanho for diferente, haverá espaço para especulações

  • a lua realmente cresce (mas o que ela come?)
  • há um efeito de lente atmosférica
  • a lua tem uma curva elíptica e às vezes está mais próxima, às vezes mais distante da terra
  • ...

Mas deixarei isso em aberto até que sua tarefa seja concluída. É claro que você deseja saber com antecedência se o seu software pode calcular o tamanho da lua com precisão.

A tarefa

Dadas algumas fotos otimizadas da lua, calcule o tamanho da lua. A otimização é: os pixels são pretos ou brancos. Nada no meio. Sem antialiasing. Isso facilita, não é?

A ressalva: a lua nem sempre está cheia, você sabe ... pode ser uma foice! Mas mesmo na forma de uma foice, o tamanho da lua é maior. Então, você calculará o tamanho completo, por favor.

  • Seu programa usa um PNG como entrada, por exemplo, como argumento da linha de comando do nome do arquivo, canalizado stdinou como um objeto Bitmap (de uma biblioteca de estrutura padrão) se você escrever uma função em vez de um programa.
  • Seu programa funciona com qualquer tamanho de bitmap de entrada razoável, não necessariamente quadrado. Largura e altura mínimas de 150 pixels são garantidas.
  • A lua cheia cobre pelo menos 25% da imagem.
  • Seu programa gera o tamanho calculado da lua em pixels como se fosse lua cheia.
  • Assumimos que a lua é uma esfera perfeita.
  • O tamanho exato é sempre um número inteiro, mas você pode gerar um número decimal se seu cálculo retornar isso.
  • A precisão deve estar entre 98% e 102%. (Isso é um palpite do que algo que eu poderia garantir que seja viável. Se você acha que é muito difícil de alcançar, por favor, deixe um comentário.)

Atualização :

  • O centro da lua não está necessariamente no meio da imagem.
  • A área mínima visível é de 5% da lua ou 1,25% do número total de pixels.
  • A foto é tirada de forma que a lua inteira se encaixe na imagem, ou seja, o número total de pixels é um limite superior para o tamanho da lua.
  • A lua não será cortada / cortada.

As amostras

Você pode gerar suas próprias amostras usando o arquivo de mistura, se desejar. Eu criei as seguintes imagens para você. Você pode contar pixels em um arquivo PNG usando o WhitePixelCounter.exe (precisa do .NET) para verificar se a imagem contém apenas pixels em preto e branco e quantos deles.

As seguintes imagens de 256x256 pixels diferem na quantidade de pixels brancos, mas devem resultar em um tamanho calculado da lua de 16416 pixels.

Lua cheia Lua Lua Lua Lua Lua

E essas imagens de 177x177 pixels devem retornar 10241 pixels. As imagens são basicamente as mesmas, mas desta vez uma câmera com uma distância focal diferente foi usada.

Lua Lua Lua Lua Lua Lua

Amostras não quadradas e não centradas, com resultado de 9988:

Lua em uma moldura não quadrada Lua em uma moldura não quadrada Lua em uma moldura não quadrada Lua em uma moldura não quadrada Lua em uma moldura não quadrada

Por enquanto, não tenho uma implementação de referência e nem sei se consigo implementar alguma coisa. Mas, no meu cérebro, existe uma forte crença que me diz que deve ser matematicamente solucionável.

As regras

Este é o Code Golf. O código mais curto de 30/03/2015 é aceito.

Thomas Weller
fonte
9
Em todos os exemplos, o centro da lua parece estar centrado na imagem. Podemos assumir que a lua sempre estará centrada?
Digital Trauma
11
sua precisão de +/- 2% na área corresponde a +/- 1% no diâmetro: exemplo r = 100 pixels, área = 10000 * pi; r = 101 pixels, área = 10201 * pi. Sua imagem menor tem r = 72, portanto, d = 144 por isso deve apenas ser possível. No entanto, para imagens abaixo de d = 100, acho que a precisão não pode ser alcançada.
Level River St
@ DigitalTrauma: o centro não precisa estar no meio.
22616 Thomas Weller #
@ MartinBüttner: a porcentagem mínima visível é de 5% da lua ou 1,25% da imagem.
22616 Thomas Weller
@ MartinBüttner: ok, atualizei a pergunta, atualizei o arquivo de mesclagem para produzir imagens não quadradas e não centralizadas por padrão. Você pode baixar todas as imagens aqui (* .png.zip) . Contador de pixels atualizado também: gera mais informações e verifica a regra de 1,25%.
21416 Thomas Weller #

Respostas:

10

Mathematica 126 119 109 bytes

O Mathematica pode medir o alongamento de um componente em uma imagem. Uma lua cheia, sendo perfeitamente simétrica, tem um alongamento de 0, em uma escala de 0 a 1.

Uma lua decrescente se torna cada vez mais alongada, até um máximo de aproximadamente 0,8.

0.998 -0.788 x-0.578 x^2 foi o modelo empiricamente determinado (baseado nas grandes fotos) para `prever a plenitude da lua (por área), dado seu alongamento.

Ajustei o modelo para 1- 0.788 x -0.578 x^2que, com alongamento exatamente zero (lua cheia), o modelo retorne 1 para o fator de escala de pixels. Ele salva 4 bytes e ainda permanece dentro dos limites de precisão.

Este modelo é usado para imagens de qualquer tamanho. A imagem da lua não precisa estar centralizada. Também não precisa cobrir uma proporção fixa da foto.

Aqui estão os pontos de dados (alongamento, exibidosMoonPixels / fullMoonPixels) para as imagens grandes e o modelo parabólico que foi gerado para ajustar os dados. Os modelos lineares se encaixam bem, mas o modelo quadrático está morto, dentro de limites (veja abaixo).

Aqui os dados são das imagens grandes. Então é o modelo

grandes crescentes


Abaixo, os dados (os pontos vermelhos) são das imagens pequenas. O modelo (a curva azul) é o gerado pelas imagens grandes, o mesmo mostrado acima.

O menor crescente tem 7,5% da área da lua cheia. (O menor crescente entre as fotos grandes é de 19% da lua cheia.) Se o modelo quadrático tivesse sido baseado nas fotos pequenas, o ajuste abaixo seria melhor, apenas porque acomodava o pequeno crescente. Um modelo robusto, que resistisse a uma ampla gama de condições, incluindo crescentes muito pequenos, seria melhor elaborado a partir de uma variedade maior de fotos.

A proximidade do ajuste mostra que o modelo não foi codificado para as fotos fornecidas. Podemos estar bastante certos de que o alongamento da lua é independente do tamanho da foto, como seria de esperar.

pequenos crescentes

fpega a imagem i,, como entrada e gera o tamanho previsto da lua cheia, em pixels. Funciona para fotos fora do centro.

Como mostram os dados abaixo, todos os casos de teste, exceto um. As luas foram organizadas do total para o mais diminuído.

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

Mais de um componente da imagem pode aparecer em uma foto. Mesmo um único pixel separado dos outros será considerado um componente distinto. Por esse motivo, é necessário pesquisar "todos" os componentes, para encontrar o que possui o maior número de pixels. (Uma das fotos pequenas possui mais de um componente de imagem.)

Imagens grandes

As previsões do tamanho da lua feitas a partir das fotos grandes eram uniformemente precisas.

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

{"tamanhos previstos de lua cheia", {16422., 16270.9, 16420.6, 16585.5, 16126.5, 16151.6}}

{"precisão", {1.00037, 0.991161, 1.00028, 1.01033, 0.982367, 0.983891}}


Imagens pequenas

As previsões do tamanho da lua feitas a partir das pequenas fotos eram uniformes, com uma grande exceção, a imagem final. Suspeito que o problema decorra do fato de o crescente ser muito estreito.

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

{"tamanhos previstos da lua cheia", {10247.3, 10161., 10265.6, 10391., 10058.9, 7045.91}}
{"precisão", {1.00061, 0.992192, 1.0024, 1.01465, 0.982221}}

DavidC
fonte
Parece que eu deveria aprender Mathematica um dia. Quanto tempo você levou para resolvê-lo sem jogar golfe?
Thomas Weller
11
@ Thomas W Demorou 2-3 horas experimentando vários tipos de recursos de processamento de imagem e outros modelos (lineares) até obter o gráfico que você vê publicado. A codificação não foi muito difícil. E quase não há golfe além de unir funções separadas em uma única função.
21415 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 razões desconhecidas, a #2&@@@sugestão não funciona #
950
Huh, vou analisar isso mais tarde. Outra maneira de encurtar céc=Max@ComponentMeasurements[##][[All,2]]&
Martin Ender
5

J, 227 207 bytes (erro máximo de 1,9%)

Minha idéia principal é que, se pudermos encontrar 3 pontos no contorno da lua, que também estão no contorno da lua cheia, poderemos calcular a circunferência desses pontos. Esse circuncisão será a lua cheia.

Se encontrarmos dois pontos brancos com distância máxima, esses serão sempre esses pontos, pois serão uma diagonal real na lua cheia ou os pontos finais do crescente. Podemos encontrar o par de pontos com a maior distância em qualquer gráfico, selecionando o ponto mais distante de qualquer ponto inicial e, em seguida, selecionando o ponto mais distante do selecionado.

Encontramos um terceiro ponto com um valor máximo dos produtos das distâncias dos pontos anteriores. Isso sempre estará no contorno e no lado externo de um crescente ou no lado maior de um gibbous.

O diâmetro do círculo é calculado como o comprimento de um lado dividido pelo seio do ângulo oposto.

A complexidade de tempo deste método é linear no tamanho da imagem 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
)

A função espera o nome do arquivo de entrada como uma sequência.

(Para uma versão (pouco) mais legível, verifique o histórico de revisões.)

Explicação do código

  • p é uma lista de coordenadas de pixel branco (chamadas de pontos no futuro)
  • A função d calcula as distâncias entre os elementos de p e um determinado ponto
  • a segunda parte da definição de s cria uma lista de 3 pontos:

    • A é o ponto mais distante do primeiro ponto da lista
    • B é o ponto mais distante de A
    • C é um ponto com um valor máximo da distância A vezes a distância de B
  • s são os comprimentos laterais do triângulo ABC

  • a última linha calcula a área do circulo do ABC, que é a lua cheia

Resultados

O maior erro é de 1,9%.

As imagens estão na mesma ordem que na pergunta.

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
fonte
+1 por participar e mencionar a abordagem. Lamento não ter especificado que o centro não precisa estar no meio. Acidentalmente, as imagens de amostra estão todas centralizadas. A culpa é minha.
Thomas Weller
@ThomasW. Excluiu temporariamente minha resposta até que eu a corrigisse.
randomra
2

Matlab 162 156 (não está exatamente na margem de erro atual)

Primeiro de tudo: a precisão é inferior a 2% para todas, exceto uma imagem em cada uma das duas séries, onde é maior (cerca de 5% e 14%). Minha abordagem foi encontrar os dois pixels da lua mais afastados um do outro e depois usá-lo como uma estimativa do 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

Estes são os resultados de precisão (desvio relativo 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
fonte
1

C # - 617

Esta solução não funciona para todas as imagens, porque em uma das imagens, a inclinação (m) torna-se infinita.

O princípio foi mencionado antes:

  1. Encontre dois pontos com distância máxima (vermelho)
  2. Imagine uma linha entre eles (vermelho)
  3. Imagine uma linha com ângulo retangular no meio (verde)
  4. Encontre pontos brancos na linha verde
  5. Use aquele com distância máxima de outros pontos (verde)
  6. Calcular a área de um círculo a partir de três pontos

Explicação

O caso problemático é este, onde a inclinação é infinita. É possível solucionar o problema girando a imagem 90 ° ou em código, faça um loop sobre o yeixo em vez de x.

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

A precisão mínima é

  • + 1,89% para as imagens de 256 pixels
  • -0,55% para as imagens de 177 pixels
  • -1,66% para imagens não quadradas
Thomas Weller
fonte