Рассчитать размер луны


19

Размер луны тайна

Я уверен, что вы слышали, что луна меняет свой размер. Когда вы влюблены и вам повезло, луна почти в два раза больше по сравнению с обычными ситуациями. Некоторые люди говорят, что причина в атмосфере, которая действует как линза. Другие считают, что это только вопрос сравнения с другими объектами, такими как деревья поблизости. Какое бы объяснение вы ни прочитали, оно весьма субъективно.

Размер луны науки

Хорошо, мы программисты, не так ли? Мы опираемся на факты, верно? Итак, вот эксперимент:

  1. Возьмите красивую камеру, которая поддерживает настройку времени и диафрагмы вручную.
  2. Установите на вашей камере максимальный уровень масштабирования.
  3. Выйдите на улицу, сделайте несколько фотографий луны, чтобы определить лучшие настройки, чтобы луна была четкой, а освещение - просто отличным.
  4. Запомнить настройки
  5. Делайте фотографии Луны с этими настройками каждый раз, когда вы думаете, что она большая или маленькая.
  6. Рассчитать размер луны в пикселях

Камера не будет врать, не так ли? Подсчитывая яркие пиксели, мы можем эффективно измерить размер луны - по крайней мере, в пикселях.

Если размер одинаков для всех фотографий, это ошибка в нашем мозгу. Если размер отличается, то есть место для спекуляций

  • Луна действительно растет (но что она ест?)
  • есть атмосферный эффект линзы
  • Луна имеет эллиптическую кривую и иногда ближе, иногда дальше от Земли
  • ...

Но я оставлю это открытым, пока ваша задача не будет выполнена. Конечно, вы хотите знать заранее, может ли ваша программа точно рассчитать размер Луны.

Задание

Учитывая несколько оптимизированных изображений луны, пожалуйста, рассчитайте размер луны. Оптимизация: пиксели либо черные, либо белые. Ничего промежуточного. Нет сглаживания. Это облегчает, не так ли?

Предостережение: луна не всегда полная, вы знаете ... это может быть серп! Но даже в форме серпа размер луны больше. Таким образом, вы рассчитаете полный размер, пожалуйста.

  • Ваша программа принимает PNG в качестве входных данных, например, в качестве аргумента командной строки имени файла, переданного по конвейеру stdinили в виде объекта Bitmap (из стандартной библиотеки фреймворка), если вы пишете функцию вместо программы.
  • Ваша программа работает с любым разумным размером входного растрового изображения, не обязательно квадратным. Минимальная ширина и высота 150 пикселей гарантированы.
  • Полная луна покрывает не менее 25% снимка.
  • Ваша программа выводит рассчитанный размер луны в пикселях, как если бы это была полная луна.
  • Мы предполагаем, что луна - идеальная сфера.
  • Точный размер всегда является целым числом, но вы можете вывести десятичное число, если ваши вычисления возвращают это.
  • Точность должна быть между 98% и 102%. (Это скорее предположение, чем то, что я могу гарантировать, чтобы быть достижимым. Если вы думаете, что это слишком сложно, пожалуйста, оставьте комментарий.)

Обновление :

  • Центр луны не обязательно находится в середине картины.
  • Минимальная видимая область составляет 5% от Луны или 1,25% от общего количества пикселей.
  • Снимок сделан таким образом, чтобы вся луна соответствовала изображению, то есть общее количество пикселей является верхней границей размера луны.
  • Луна не будет обрезана / обрезана.

Образцы

Вы можете создавать свои собственные образцы, используя файл blend, если хотите. Я создал следующие картинки для вас. Вы можете сосчитать пиксели в PNG-файле, используя WhitePixelCounter.exe (требуется .NET), чтобы проверить, содержит ли изображение только черные и белые пиксели и сколько их.

Следующие изображения размером 256x256 пикселей отличаются по количеству белых пикселей, но все они должны привести к расчетному размеру луны 16416 пикселей.

Полнолуние Луна Луна Луна Луна Луна

И эти 177x177 пикселей изображения должны возвращать 10241 пикселей. Изображения в основном одинаковые, но на этот раз использовалась камера с другим фокусным расстоянием.

Луна Луна Луна Луна Луна Луна

Неквадратные и нецентрированные образцы с результатом 9988:

Луна в неквадратной рамке Луна в неквадратной рамке Луна в неквадратной рамке Луна в неквадратной рамке Луна в неквадратной рамке

О, у меня пока нет эталонной реализации, и я даже не знаю, могу ли я что-то реализовать. Но в моем мозгу есть сильное убеждение, которое говорит мне, что это должно быть математически разрешимо.

Правила

Это Код Гольф. Самый короткий код на 2015-03-30 принимается.


9
Во всех примерах центр луны, кажется, центрирован в пределах изображения. Можем ли мы предположить, что луна всегда будет в центре?
Цифровая травма

1
Ваша точность +/- 2% по площади соответствует +/- 1% по диаметру: пример r = 100 пикселей, площадь = 10000 * пи; r = 101 пиксель, площадь = 10201 * пи. Ваше маленькое изображение имеет r = 72, поэтому d = 144, так что это должно быть просто возможно. Однако для изображений ниже d = 100 точность не может быть достигнута.
Уровень Река St

@DigitalTrauma: центр не должен быть посередине.
Томас Уэллер

@ MartinBüttner: минимальный видимый процент составляет 5% от Луны или 1,25% изображения.
Томас Веллер

@ MartinBüttner: хорошо, я обновил вопрос, обновил файл наложения, чтобы по умолчанию получать не квадратные, не центрированные изображения. Вы можете скачать все изображения здесь (* .png.zip) . Также обновлен счетчик пикселей: выводит дополнительную информацию и проверяет правило 1.25%.
Томас Веллер

Ответы:


10

Mathematica 126 119 109 байтов

Mathematica может измерять удлинение компонента в изображении. Полнолуние, будучи абсолютно симметричным, имеет удлинение 0 по шкале от 0 до 1.

Уменьшающаяся луна становится все более вытянутой, максимально до 0,8.

0.998 -0.788 x-0.578 x^2 была эмпирически определенная модель (на основе больших фотографий) для «предсказания полноты луны (по площади) с учетом ее удлинения.

Я настроил модель 1- 0.788 x -0.578 x^2так, чтобы при нулевом удлинении (полная луна) модель вернула 1 для масштабного коэффициента пикселей. Он сохраняет 4 байта и остается в пределах точности.

Эта модель используется для изображений любого размера. Изображение луны не нужно центрировать. Также не нужно покрывать фиксированную пропорцию фотографии.

Вот точки данных (удлинение, displayMoonPixels / fullMoonPixels) для больших изображений и параболическая модель, которая была создана для соответствия данным. Линейные модели подходят нормально, но квадратичная модель не работает в определенных пределах (см. Ниже).

Здесь данные из больших картинок. Так и модель

большие полумесяцы


Ниже данные (красные точки) взяты из маленьких картинок. Модель (синяя кривая) - это модель, созданная большими изображениями, такая же, как показано выше.

Самый маленький полумесяц имеет 7,5% площади полной луны. (Самый маленький полумесяц среди больших фотографий составляет 19% от полной луны.) Если бы квадратичная модель была основана на маленьких фотографиях, подгонка ниже была бы лучше, только потому, что она вмещала маленький полумесяц. Надежная модель, которая будет выдерживать самые разные условия, в том числе очень маленькие полумесяцы, будет лучше сделана из более разнообразных изображений.

Близость соответствия показывает, что модель не была жестко запрограммирована для данных изображений. Мы можем быть совершенно уверены, что удлинение луны не зависит от размера фотографии, как можно было бы ожидать.

маленькие полумесяцы

fпринимает изображение в iкачестве входных данных и выводит прогнозируемый размер полной луны в пикселях. Это работает для выстрелов вне центра.

Как показывают данные ниже, это все тестовые случаи, кроме одного. Луны были расположены от полного до наиболее уменьшенного.

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

На фотографии может появиться несколько компонентов изображения. Даже один пиксель, отделенный от других, будет считаться отдельным компонентом. По этой причине необходимо искать «все» компоненты, чтобы найти тот, который имеет большее количество пикселей. (Одна из маленьких фотографий содержит более одного компонента изображения.)

Большие картинки

Предсказания размера луны, сделанные на больших фотографиях, были одинаково точными.

{"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}}


Маленькие картинки

Предсказания о размере луны, сделанные на маленьких фотографиях, были однородными, за одним большим исключением, окончательной картиной. Я подозреваю, что проблема связана с тем, что полумесяц очень узкий.

{"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.0024, 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

Да, я посмотрю на это позже. Другой способ сократить cэтоc=Max@ComponentMeasurements[##][[All,2]]&
Мартин Эндер

5

J 227 207 байт (максимальная ошибка 1,9%)

Моя основная идея состоит в том, что если мы можем найти 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 создает список из 3 пунктов:

    • А - самая дальняя точка от первой точки в списке
    • 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 за участие и упоминание подхода. Извините, я не указал, что центр не должен быть посередине. Случайно образцы изображений все по центру. Это моя ошибка.
Томас Веллер

@ThomasW. Временно удалил мой ответ, пока я не исправлю его.
Рандомара

2

Matlab 162 156 (не совсем в текущей погрешности)

Прежде всего: точность составляет менее 2% для всех изображений, кроме одного, в каждой из двух серий, где она выше (около 5% и 14%). Мой подход заключался в том, чтобы найти два пикселя луны, которые находятся дальше всего друг от друга, а затем использовать это как оценку диаметра.

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

Это решение не работает для всех изображений, потому что на одном из изображений наклон (m) становится бесконечным.

Принцип был упомянут ранее:

  1. Найти две точки с максимальным расстоянием (красный)
  2. Представьте линию между ними (красная)
  3. Представьте линию с прямоугольным углом посередине (зеленая)
  4. Найдите белые точки на зеленой линии
  5. Используйте тот с максимальным расстоянием от других точек (зеленый)
  6. Рассчитайте площадь круга из трех точек

объяснение

Проблемным случаем является тот, где уклон бесконечен. Это можно обойти, повернув изображение на 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;}

Минимальная точность

  • + 1,89% для изображений с разрешением 256 пикселей
  • -0,55% для изображений 177 пикселей
  • -1,66% для неквадратных изображений
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.