这是我想做的:
我定期用网络摄像头拍照。有点像时间流逝的东西。但是,如果真的什么都没有改变,也就是说,图片 看起来 几乎一样,我不想存储最新的快照。
我想有某种方法可以量化差异,我将不得不凭经验确定一个阈值。
我正在寻找简单而不是完美。我正在使用蟒蛇。
原文由 carrier 发布,翻译遵循 CC BY-SA 4.0 许可协议
这是我想做的:
我定期用网络摄像头拍照。有点像时间流逝的东西。但是,如果真的什么都没有改变,也就是说,图片 看起来 几乎一样,我不想存储最新的快照。
我想有某种方法可以量化差异,我将不得不凭经验确定一个阈值。
我正在寻找简单而不是完美。我正在使用蟒蛇。
原文由 carrier 发布,翻译遵循 CC BY-SA 4.0 许可协议
2 回答5.2k 阅读✓ 已解决
2 回答1.1k 阅读✓ 已解决
4 回答1.4k 阅读✓ 已解决
3 回答1.3k 阅读✓ 已解决
3 回答1.3k 阅读✓ 已解决
2 回答884 阅读✓ 已解决
1 回答1.8k 阅读✓ 已解决
大概的概念
选项 1:将两个图像加载为数组 (
scipy.misc.imread
) 并计算逐元素(逐像素)差异。计算差值的范数。选项 2:加载两个图像。为它们中的每一个计算一些特征向量(如直方图)。计算特征向量而不是图像之间的距离。
但是,首先要做出一些决定。
问题
你应该首先回答这些问题:
如果不是,您可能需要调整它们的大小或裁剪它们。 PIL 库将有助于在 Python 中完成它。
如果它们是使用相同的设置和相同的设备拍摄的,则它们可能是相同的。
如果不是,您可能需要先运行互相关,首先找到最佳对齐方式。 SciPy 具有执行此操作的功能。
如果相机和场景是静止的,则图像很可能对齐良好。
如果不是,您可能需要 规范化 图像。
但要小心,在某些情况下,这样做可能弊大于利。例如,黑暗背景上的单个明亮像素会使归一化图像有很大差异。
如果您想注意颜色变化,您将拥有每个点的颜色值向量,而不是灰度图像中的标量值。编写此类代码时需要多加注意。
如果是,您可以首先应用边缘检测算法(例如使用 Sobel 或 Prewitt 变换计算梯度,应用一些阈值),然后将第一张图像的边缘与第二张图像的边缘进行比较。
所有传感器都会用一定量的噪声污染图像。低成本传感器的噪声更大。在比较图像之前,您可能希望应用一些降噪。模糊是这里最简单(但不是最好)的方法。
这可能会影响用于图像之间差异的范数的选择。
考虑使用曼哈顿范数(绝对值之和)或零范数(不等于零的元素数)来衡量图像发生了多少变化。前者会告诉您图像偏离了多少,后者只会告诉您有多少像素不同。
例子
我假设您的图像对齐良好,大小和形状相同,可能曝光不同。为简单起见,我将它们转换为灰度,即使它们是彩色 (RGB) 图像也是如此。
您将需要这些导入:
主要功能,读取两张图片,转灰度,比较打印结果:
如何比较。
img1
和img2
是二维 SciPy 数组:如果文件是彩色图像,
imread
返回一个3D数组,平均RGB通道(最后一个数组轴)得到强度。无需为灰度图像执行此操作(例如.pgm
):归一化很简单,您可以选择归一化为 [0,1] 而不是 [0,255]。
arr
在这里是一个 SciPy 数组,所以所有操作都是按元素进行的:运行
main
函数:现在你可以把这一切放在一个脚本中并针对两个图像运行。如果我们将图像与自身进行比较,则没有区别:
如果我们模糊图像并与原始图像进行比较,则存在一些差异:
PS 整个 compare.py 脚本。
更新:相关技巧
由于问题是关于视频序列的,其中帧可能几乎相同,并且您正在寻找不寻常的东西,因此我想提及一些可能相关的替代方法:
我强烈建议看一看“学习 OpenCV”一书,第 9 章(图像部分和分割)和第 10 章(跟踪和运动)。前者教导使用背景减法,后者给出一些关于光流法的信息。所有方法都在 OpenCV 库中实现。如果你使用 Python,我建议使用 OpenCV ≥ 2.3,及其
cv2
Python 模块。背景减除的最简单版本:
更高级的版本会考虑每个像素的时间序列并处理非静态场景(如移动的树木或草地)。
光流的思想是获取两个或更多帧,并将速度矢量分配给每个像素(密集光流)或其中的一些(稀疏光流)。要估计稀疏光流,您可以使用 Lucas-Kanade 方法(它也在 OpenCV 中实现)。显然,如果有很多流量(速度场的平均值超过最大值),那么帧中有东西在移动,后续图像就会更加不同。
比较直方图可能有助于检测连续帧之间的突然变化。 Courbon 等人在 2010 年 使用了这种方法: