计算月亮的大小


19

月球之谜的大小

我相信您已经听说月亮改变了它的大小。当您恋爱了并且很幸运时,月亮的大小几乎是正常情况下的两倍。有人说,原因是大气充当了镜头。其他人则认为,这仅仅是与附近树木等其他物体进行比较的问题。无论您阅读了什么说明,都是相当主观的。

月球科学的大小

好吧,我们是程序员,不是吗?我们依靠事实,对吗?所以这是实验:

  1. 拿一个不错的相机,它支持手动设置时间和光圈。
  2. 将相机设置为最大变焦等级。
  3. 外出时,为月亮拍摄一些照片,以检测最佳设置,以使月亮清晰且光线充足。
  4. 记住设置
  5. 每当您认为月球大小时,都使用这些设置为月球拍照。
  6. 计算月亮的大小(以像素为单位)

相机不会说谎,是吗?通过计算明亮的像素,我们可以有效地测量月亮的大小-至少以像素为单位。

如果所有照片的大小都相同,那么这就是我们大脑中的错误。如果大小不同,那么就有炒作的空间

  • 月亮真的长了(但是它吃什么?)
  • 有大气的镜头效果
  • 月亮呈椭圆形,有时更近,有时更远离地球
  • ...

但是我将保持打开状态,直到您的任务完成。当然,您想事先知道您的软件是否可以准确计算月球尺寸。

任务

给定一些优化的月球图片,请计算月球的大小。优化是:像素为黑色或白色。两者之间什么都没有。没有抗锯齿。这很容易,不是吗?

注意事项:月亮并不总是充满,您知道...它可能是镰刀!但是即使是镰刀形状,月亮的大小也会更大。因此,请计算出完整尺寸。

  • stdin如果您编写的是函数而不是程序,则程序将PNG作为输入,例如作为文件名命令行参数,通过管道传输到(或作为标准框架库的)Bitmap对象。
  • 您的程序可以使用任何合理的输入位图大小,而不必是正方形。保证最小宽度和高度为150像素。
  • 满月至少覆盖了图片的25%。
  • 您的程序将以像素为单位输出计算出的月亮大小,就好像它是满月一样。
  • 我们假设月亮是一个完美的球体。
  • 确切的大小始终是整数,但是如果计算返回该数字,则可以输出一个十进制数。
  • 精度应在98%到102%之间。(这只是一个猜测,而不是我可以保证可以实现的目标。如果您认为很难实现,请发表评论。)

更新

  • 月亮的中心不一定在图片的中间。
  • 最小可见区域为月球的5%或像素总数的1.25%。
  • 以使整个月亮适合图像的方式拍摄照片,即,像素总数是月亮大小的上限。
  • 月亮不会被裁剪/修剪。

样品

如果愿意,您可以使用混合文件生成自己的样本。我为您制作了以下图片。您可以使用WhitePixelCounter.exe(需要.NET)对PNG文件中的像素进行计数,以检查图像是否仅包含黑白像素以及它们包含多少个。

以下256x256像素图像的白色像素数量有所不同,但所有这些图像的计算出的月亮大小应为16416像素。

满月 月亮 月亮 月亮 月亮 月亮

这些177x177像素的图像应返回10241像素。图像基本相同,但是这次使用的是焦距不同的相机。

月亮 月亮 月亮 月亮 月亮 月亮

结果为9988的非正方形和非中心样本:

非方形框架中的月亮 非方形框架中的月亮 非方形框架中的月亮 非方形框架中的月亮 非方形框架中的月亮

哦,我目前没有参考实现,我什至不知道我是否能够实现某些功能。但是在我的大脑中,有一个强烈的信念告诉我它必须在数学上可以解决。

规则

这是Code Golf。2015-03-30上最短的代码被接受。


9
在所有示例中,月亮的中心似乎位于图片的中心。我们可以假设月亮将始终居中吗?
Digital Trauma 2015年

1
您的区域精度+/- 2%相当于直径的+/- 1%:例如r = 100像素,区域= 10000 * pi;r = 101像素,面积= 10201 * pi。您的较小的图像具有R = 72因此当d = 144,所以应该只是是可能的。但是,对于d = 100以下的图像,我认为精度无法满足。
级圣河

@DigitalTrauma:中心不必在中间。
Thomas Weller 2015年

@MartinBüttner:最小可见百分比是月球的5%或图片的1,25%。
Thomas Weller

@MartinBüttner:好的,我已经更新了问题,更新了混合文件,默认情况下会生成非正方形,非居中图像。您可以在此处下载所有图像(* .png.zip)。同时更新了像素计数器:输出更多信息并检查1.25%规则。
Thomas Weller

Answers:


10

Mathematica 126119109字节

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个字节,仍然保持在精度范围内。

该模型可用于任何尺寸的图像。月亮图像不需要居中。它还不需要覆盖照片的固定比例。

这是大图像的数据点(伸长率,displaydMoonPixels / 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。您不打高尔夫球花了多长时间解决?
Thomas Weller

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

嗯,我稍后再研究。另一种缩短的方法cc=Max@ComponentMeasurements[##][[All,2]]&
Martin Ender

5

J,227207字节(最大错误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定义的第二部分创建一个三点列表:

    • A是距离列表中第一点最远的点
    • 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以参与和提及该方法。抱歉,我没有指定中心不必在中间。偶然地,样本图像全部居中。这是我的错。
Thomas Weller 2015年

@ThomasW。暂时删除我的答案,直到我更正为止。
randomra 2015年

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

最低精度是

  • 256像素图像为+ 1,89%
  • 177个像素的图像为-0.55%
  • 非正方形图像为-1.66%
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.