数字照片中,如何检测山是否被云层遮挡?

27

问题

我有一组日本一座山的数字照片。然而,这座山经常被云雾遮挡。

我可以使用哪些技术来检测图像中山是否可见?我目前正在使用带有Imager模块的Perl,但也愿意尝试其他方法。

所有的图片都是从同一个位置拍摄的-这是一些样本。

示例图片http://www.freeimagehosting.net/uploads/7304a6e191.jpg

我的天真解决方案

我开始对山锥进行多个水平像素样本,并将亮度值与天空的其他样本进行比较。这对于区分好的图像1和坏的图像2效果很好。

然而,在秋季下雪后,山变得比天空更亮,就像图3一样,我的简单亮度测试开始失败。

图4是一个边缘情况的例子。我会将其分类为好的图像,因为山的某些部分明显可见。

更新1

感谢您的建议-我很高兴你们都大大高估了我的能力。

根据答案,我已经开始尝试使用ImageMagick边缘检测转换,这给了我一个更简单的图像来分析。

convert sample.jpg -edge 1 edge.jpg

检测边缘样本 http://www.freeimagehosting.net/uploads/caa9018d84.jpg

我认为我应该使用某种掩蔽来消除树木和大部分云层。

一旦我有了掩蔽图像,最好的方法是如何将其与“好”图像进行比较?我想“比较”命令适合这项工作?我如何从中获得数值“相似度”?

更新2

我想我可能正在使用卷积。

我通过对良好图像执行边缘检测来制作我的“内核”图像(下面的图像顶部)。然后,我在山的轮廓周围涂黑了所有的“噪声”,然后将其裁剪。

然后我使用了以下代码:

use Image::Magick;

# Edge detect the test image
my $test_image = Image::Magick->new;
$test_image->Read($ARGV[0]);
$test_image->Quantize(colorspace=>'gray');
$test_image->Edge(radius => 1);

# Load the kernel
my $kernel_image = Image::Magick->new;
$kernel_image->Read('kernel-crop.jpg');

# Convolve and show the result
$kernel_image->Convolve(coefficients => [$test_image->GetPixels()]);
$kernel_image->Display();

我对各种样本图像运行了此操作,并获得了以下结果(每个样本下方显示了卷积后的图像):

(抱歉-与上次不同的样本图像!)

alt text http://www.freeimagehosting.net/uploads/f9a5a34980.jpg

现在我正在尝试量化图像的“崎岖程度”。 我尝试获取图像的平均亮度:

$kernel_image->Scale('1x1');
die $kernel_image->GetPixel(x=>1,y=>1)[0];

但是这样做并不能得到有意义的值(0.0165、0.0175 和 0.0174)。还有更好的方法吗?

4
非常好的提问,表达清晰易懂。 - msw
1
你低估了自己的能力。更新1中“比较”链接提供了许多非常好的方法,可以通过卷积生成相似性度量,就像Marcelo建议的那样。我想当我打字时你正在尝试调整它们。 - msw
3个回答

9

我认为你的工作层次太低了。通过快速通过边缘检测滤波器的处理,可以将图像集明显地分成(1, 3)和(2, 4)两部分。特别是如果这些图像来自固定的相机视角,那么算法上找到与(1)中的原型形状匹配的图像将会相对容易。即使是你的情况(4),也可以给你一个部分匹配的领域,你可以根据启发式方法确定是否有足够的山峰来考虑。


谢谢 - 我已经开始尝试边缘检测并更新了问题。但仍然有些困惑如何量化山的大小。 - Gavin Brock

5
一些具体的建议,基于您已有的东西:
1.选取最佳图片(类似图像1),运行边缘检测,用任何图形编辑器打开结果(MS Paint就可以),清除除山顶边界以外的所有内容(“中国帽”线)。这是卷积核。您可以从上方和下方进行裁剪(不要调整大小!)以在下一步节省一些时间。
2.使用PerlMagick中的Convolve函数(您似乎已经熟悉Perl和ImageMagick)将核与一些图像进行卷积。在结果图像上,您应该看到与核的“正确”位置(与图像中的山峰重合)相对应的尖锐峰值。
3.这种峰值的相对高度(相对于周围噪声的水平)将在山峰更为清晰可见时更大。通过选择几个代表性图像,您可能能够确定将好图像与坏图像分离的阈值。
4.无论您做什么,都会出现假阳性和假阴性。请做好准备。

感谢提供逐步指南。对于我目前的水平来说,这真的非常有帮助。但是,我有点不确定第二步是如何工作的 - 我该如何将“内核”图像传递给卷积函数 - 它似乎只接受系数矩阵? - Gavin Brock
@Gavin:内核==矩阵。我已经尝试为您找到一些关于卷积的合适解释,但是没有找到任何东西--也许您应该自己尝试一下。 - AVB
经过很多尝试,我使用了$test_image->GetPixels()作为系数 - 这样做有效吗?我再次更新了帖子。 - Gavin Brock
看起来它能工作,干得好。虽然这并不是很重要,但你应该把卷积反过来做,像这样 test_image->Convolve(coefficients => [$kernel_image->GetPixels()]);。另外,你确定 Scale('1x1') 能给出平均亮度吗?无论如何,类似于90分位数的指标比平均值更好。 - AVB

4
答案取决于问题的具体性质。如果是同一座山从同一视角,可以对已知好的图像进行运行和边缘检测,并将其用作对语料库中的边缘检测图像进行卷积的基线。如果只关注山的边缘,则需要手动从基线中删除其他特征。

1
谢谢。幸运的是,问题非常具体 - 视角是固定的。边缘检测似乎是开始的正确位置。我对卷积部分有点不确定。 - Gavin Brock
抱歉回复晚了,时区不同。两张图像的卷积将展示出一些指示某种相似性的尖峰。如果你只想知道是否足够看到整座山,计算仅包含山脉边缘的图像和你正在测试的图像之间的卷积即可。图像中心附近的强烈尖峰将告诉你一切。 - Marcelo Cantos

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接