这是我想做的:
我定期用网络摄像头拍照。就像时间流逝一样。然而,如果没有什么真正的改变,也就是说,图片看起来几乎相同,我不想存储最新的快照。
我想有某种方法可以量化这种差异,我必须根据经验确定一个阈值。
我追求的是简单而不是完美。 我用的是python。
这是我想做的:
我定期用网络摄像头拍照。就像时间流逝一样。然而,如果没有什么真正的改变,也就是说,图片看起来几乎相同,我不想存储最新的快照。
我想有某种方法可以量化这种差异,我必须根据经验确定一个阈值。
我追求的是简单而不是完美。 我用的是python。
当前回答
两种流行且相对简单的方法是:(a)已经提出的欧几里得距离,或(b)标准化互相关。与简单的互相关相比,归一化互相关对光照变化的影响明显更强。维基百科给出了一个标准化互相关的公式。更复杂的方法也存在,但它们需要更多的工作。
使用numpy-like语法,
dist_euclidean = sqrt(sum((i1 - i2)^2)) / i1.size dist_manhattan = sum(abs(i1 - i2)) / i1.size dist_ncc = sum( (i1 - mean(i1)) * (i2 - mean(i2)) ) / ( (i1.size - 1) * stdev(i1) * stdev(i2) )
假设i1和i2为二维灰度图像阵列。
其他回答
另一个衡量两张图片相似度的好方法是:
import sys
from skimage.measure import compare_ssim
from skimage.transform import resize
from scipy.ndimage import imread
# get two images - resize both to 1024 x 1024
img_a = resize(imread(sys.argv[1]), (2**10, 2**10))
img_b = resize(imread(sys.argv[2]), (2**10, 2**10))
# score: {-1:1} measure of the structural similarity between the images
score, diff = compare_ssim(img_a, img_b, full=True)
print(score)
如果其他人对更强大的比较图像相似性的方法感兴趣,我将使用Tensorflow测量和可视化相似图像的教程和web应用程序放在一起。
看看Haar小波是如何由isk-daemon实现的。你可以使用它的imgdb c++代码来实时计算图像之间的差异:
disk -daemon是一个开源的数据库服务器,能够将基于内容的(可视的)图像搜索添加到任何与图像相关的网站或软件。 这项技术允许任何与图像相关的网站或软件的用户在小部件上绘制他们想要查找的图像,并让网站回复他们最相似的图像或简单地在每个图像详细页面请求更多相似的照片。
一般的想法
选项1:以数组的形式加载两个图像(scipy.misc.imread),并计算逐元素(逐像素)的差值。计算差值的范数。
选项2:加载两个图像。计算每个特征向量(如直方图)。计算特征向量而不是图像之间的距离。
然而,首先要做一些决定。
问题
你应该先回答这些问题:
Are images of the same shape and dimension? If not, you may need to resize or crop them. PIL library will help to do it in Python. If they are taken with the same settings and the same device, they are probably the same. Are images well-aligned? If not, you may want to run cross-correlation first, to find the best alignment first. SciPy has functions to do it. If the camera and the scene are still, the images are likely to be well-aligned. Is exposure of the images always the same? (Is lightness/contrast the same?) If not, you may want to normalize images. But be careful, in some situations this may do more wrong than good. For example, a single bright pixel on a dark background will make the normalized image very different. Is color information important? If you want to notice color changes, you will have a vector of color values per point, rather than a scalar value as in gray-scale image. You need more attention when writing such code. Are there distinct edges in the image? Are they likely to move? If yes, you can apply edge detection algorithm first (e.g. calculate gradient with Sobel or Prewitt transform, apply some threshold), then compare edges on the first image to edges on the second. Is there noise in the image? All sensors pollute the image with some amount of noise. Low-cost sensors have more noise. You may wish to apply some noise reduction before you compare images. Blur is the most simple (but not the best) approach here. What kind of changes do you want to notice? This may affect the choice of norm to use for the difference between images. Consider using Manhattan norm (the sum of the absolute values) or zero norm (the number of elements not equal to zero) to measure how much the image has changed. The former will tell you how much the image is off, the latter will tell only how many pixels differ.
例子
我假设你的照片对齐得很好,同样的大小和形状,可能曝光不同。为了简单起见,我将它们转换为灰度,即使它们是彩色(RGB)图像。
您将需要这些导入:
import sys
from scipy.misc import imread
from scipy.linalg import norm
from scipy import sum, average
主要功能,读取两幅图像,转换为灰度,比较并打印结果:
def main():
file1, file2 = sys.argv[1:1+2]
# read images as 2D arrays (convert to grayscale for simplicity)
img1 = to_grayscale(imread(file1).astype(float))
img2 = to_grayscale(imread(file2).astype(float))
# compare
n_m, n_0 = compare_images(img1, img2)
print "Manhattan norm:", n_m, "/ per pixel:", n_m/img1.size
print "Zero norm:", n_0, "/ per pixel:", n_0*1.0/img1.size
如何比较。img1和img2是这里的2D SciPy数组:
def compare_images(img1, img2):
# normalize to compensate for exposure difference, this may be unnecessary
# consider disabling it
img1 = normalize(img1)
img2 = normalize(img2)
# calculate the difference and its norms
diff = img1 - img2 # elementwise for scipy arrays
m_norm = sum(abs(diff)) # Manhattan norm
z_norm = norm(diff.ravel(), 0) # Zero norm
return (m_norm, z_norm)
如果文件是彩色图像,imread返回一个3D数组,平均RGB通道(最后一个数组轴)获得强度。对于灰度图像(例如.pgm)不需要这样做:
def to_grayscale(arr):
"If arr is a color image (3D array), convert it to grayscale (2D array)."
if len(arr.shape) == 3:
return average(arr, -1) # average over the last axis (color channels)
else:
return arr
归一化是微不足道的,您可以选择归一化为[0,1]而不是[0,255]。arr在这里是一个SciPy数组,所以所有的操作都是与元素相关的:
def normalize(arr):
rng = arr.max()-arr.min()
amin = arr.min()
return (arr-amin)*255/rng
运行main函数:
if __name__ == "__main__":
main()
现在,您可以将所有这些放在一个脚本中,并针对两个图像运行。如果我们比较image和它本身,没有区别:
$ python compare.py one.jpg one.jpg
Manhattan norm: 0.0 / per pixel: 0.0
Zero norm: 0 / per pixel: 0.0
如果我们将图像模糊并与原始图像进行比较,会有一些差异:
$ python compare.py one.jpg one-blurred.jpg
Manhattan norm: 92605183.67 / per pixel: 13.4210411116
Zero norm: 6900000 / per pixel: 1.0
P.S.完整的compare.py脚本。
更新:相关技术
因为这个问题是关于视频序列的,其中帧可能几乎相同,并且你在寻找一些不寻常的东西,我想提到一些可能相关的替代方法:
背景减法和分割(用于检测前景对象) 稀疏光流(用于检测运动) 比较直方图或其他统计数据,而不是图像
我强烈建议你看一看“学习OpenCV”的书,第9章(图像部分和分割)和第10章(跟踪和运动)。前者介绍了背景减法,后者介绍了光流法。所有方法都在OpenCV库中实现。如果你使用Python,我建议使用OpenCV≥2.3,以及它的cv2 Python模块。
背景减法最简单的版本:
学习背景中每个像素的平均值μ和标准差σ 将当前像素值与(μ-2σ,μ+2σ)或(μ-σ,μ+σ)范围进行比较
更高级的版本会考虑每个像素的时间序列,并处理非静态场景(如移动的树或草)。
光流的思想是取两个或两个以上的帧,并将速度向量分配给每个像素(密集光流)或其中的一些像素(稀疏光流)。要估计稀疏光流,可以使用Lucas-Kanade方法(它也在OpenCV中实现)。显然,如果有很多流动(速度场的高平均值超过最大值),那么帧中就有东西在移动,随后的图像就会更不同。
比较直方图可以帮助检测连续帧之间的突然变化。Courbon等人在2010年使用了这种方法:
连续帧的相似度。测量两个连续帧之间的距离。如果它太高,这意味着第二帧被损坏,因此图像被消除。两帧直方图上的Kullback-Leibler距离,或相互熵: 其中p和q是帧的直方图。阈值固定在0.2。
如果现在回复太晚,我很抱歉,但因为我一直在做类似的事情,我想我可以在某种程度上做出贡献。
也许在OpenCV中你可以使用模板匹配。假设你用的是摄像头
简化图像(可能是阈值?) 应用模板匹配和检查max_val与minMaxLoc
提示:max_val(或min_val取决于所使用的方法)将为您提供数字,较大的数字。为了获得百分比上的差异,使用与相同图像匹配的模板—结果将是100%。
举例的伪代码:
previous_screenshot = ...
current_screenshot = ...
# simplify both images somehow
# get the 100% corresponding value
res = matchTemplate(previous_screenshot, previous_screenshot, TM_CCOEFF)
_, hundred_p_val, _, _ = minMaxLoc(res)
# hundred_p_val is now the 100%
res = matchTemplate(previous_screenshot, current_screenshot, TM_CCOEFF)
_, max_val, _, _ = minMaxLoc(res)
difference_percentage = max_val / hundred_p_val
# the tolerance is now up to you
希望能有所帮助。
如何计算这两幅图像的曼哈顿距离呢?得到n*n个值。然后你可以做一些事情,比如行平均,把值减少到n个,然后再用一个函数得到一个值。