如何检测两幅PIL图像之间的运动?(包括wxPython网络摄像头集成示例)

如何检测两幅PIL图像之间的运动?(包括wxPython网络摄像头集成示例),python,wxpython,webcam,python-imaging-library,video-capture,Python,Wxpython,Webcam,Python Imaging Library,Video Capture,对于如何用python进行图像比较以检测图像中的更改,有人有什么建议吗?我目前正在开发一个应用程序,可以用我的网络摄像头监控我的区域,我想知道如何比较每帧拍摄的图像,看看是否检测到任何运动。从长远来看,我想设置一个灵敏度滑块,这样,如果你能引导我的方向,我相信我可以找出其余的 正如我在这里看到的一些帖子询问如何将网络摄像头与wxPython集成,这里有一个小演示。请注意,我昨晚刚刚开始编写,所以如果您正在寻找提示顶级代码,您可能需要自己修改它(目前;): 要求: *更新* 使用Paul的示例,我

对于如何用python进行图像比较以检测图像中的更改,有人有什么建议吗?我目前正在开发一个应用程序,可以用我的网络摄像头监控我的区域,我想知道如何比较每帧拍摄的图像,看看是否检测到任何运动。从长远来看,我想设置一个灵敏度滑块,这样,如果你能引导我的方向,我相信我可以找出其余的

正如我在这里看到的一些帖子询问如何将网络摄像头与wxPython集成,这里有一个小演示。请注意,我昨晚刚刚开始编写,所以如果您正在寻找提示顶级代码,您可能需要自己修改它(目前;):

要求:

*
更新
*

使用Paul的示例,我创建了一个类并将其实现到我的代码中:

class Images:

    def __init__(self, image1, image2, threshold=98, grayscale=True):
        self.image1 = image1
        if type(image1) == str:
            self.image1 = Image.open(self.image1)
        self.image2 = image2
        if type(image2) == str:
            self.image2 = Image.open(image2)
        self.threshold = threshold

    def DoComparison(self, image1=None, image2=None):
        if not image1: image1 = self.image1
        if not image2: image2 = self.image2
        diffs = ImageChops.difference(image1, image2)
        return self.ImageEntropy(diffs)

    def ImageEntropy(self, image):
        histogram   = image.histogram()
        histlength  = sum(histogram)
        probability = [float(h) / histlength for h in histogram]
        return -sum([p * math.log(p, 2) for p in probability if p != 0])
然后将变量self.image=False添加到VideoCapturatRead的
\uuu init\uuu()
函数中,并将以下代码添加到VideoCapturatRead的run()函数的im=image.fromstring(…)行之后:

        if self.image:
            img = compare.Images2(im, self.image).DoComparison()
            print img
        self.image = im
当我运行示例时,它似乎工作正常,但我对得到的结果有点困惑:

1.58496250072
5.44792407663
1.58496250072
5.44302784225
1.58496250072
5.59144486002
1.58496250072
5.37568050189
1.58496250072
到目前为止,似乎每一个其他的图像是关闭了相当一点,虽然变化是最小的?理论上,添加到run中应该捕获变量self.image下的前一个图像,并与新图像im进行比较。比较之后,self.image使用self.image=im更新为当前图像,那么为什么每秒钟的图像都会有这样的差异呢?最多我的眼睛可能在这两幅图像中前后移动,我看不出这会导致我的结果如此不同

*
更新2
*

到目前为止,我有三个比较类,它们有三种不同的方法来检测运动

类图像~我第一次尝试使用谷歌搜索时发现的一些代码,甚至记不起它是如何工作的P

使用Paul在此线程中的代码创建类Images2,实现其更新的图像熵函数

class Images3~找到DetectMotion函数的修改版本。(返回已更改的百分比,并且似乎考虑了照明)

老实说,我真的不知道他们中的任何一个在做什么,但我能说的是,到目前为止,类Image3似乎是设置检测的最简单/准确的方法,缺点是它比其他两个类需要更多的时间来处理

(请注意,进行了一些导入更改以避免与scipy发生冲突,sys.modules[“Image”]与PIL.Image相同)

将数学、系统、numpy导入为np
导入PIL.Image,PIL.ImageChops
系统模块[“映像”]=PIL.Image
系统模块[“ImageChops”]=PIL.ImageChops
从scipy.misc导入imread
来自scipy.linalg导入规范
从scipy导入总和,平均值
默认设备宽度=640
默认设备高度=480
类图像:
def u u init u u;(self,image1,image2,阈值=98,灰度=True):
如果类型(图像1)=str:
self.image1=sys.modules[“Image”]。打开(image1)
self.image2=sys.modules[“Image”]。打开(image2)
如果为灰度:
self.image1=self.DoGrayscale(imread(image1).astype(float))
self.image2=self.DoGrayscale(imread(image2).astype(float))
其他:
self.image1=imread(image1).astype(float)
self.image2=imread(image2).astype(float)
self.threshold=阈值
def文档比较(self,image1=None,image2=None):
如果image1:image1=self.Normalize(image1)
else:image1=self.Normalize(self.image1)
如果image2:image2=self.Normalize(image2)
else:image2=self.Normalize(self.image2)
差异=图像1-图像2
m_范数=总和(绝对值(差值))
z_norm=norm(diff.ravel(),0)
返回(m_范数,z_范数)
def DoGrayscale(自身、arr):
如果len(arr.shape)==3:
返回平均值(arr,-1)
其他:
返回arr
def正常化(自身、arr):
rng=arr.max()-arr.min()
阿明=到达最小值()
返回(arr-amin)*255/rng
类别图像2:
def u u init u u;(self,image1,image2,阈值=98,灰度=True):
self.image1=image1
如果类型(图像1)=str:
self.image1=sys.modules[“Image”]。打开(self.image1)
self.image2=image2
如果类型(图像2)=str:
self.image2=sys.modules[“Image”]。打开(image2)
self.threshold=阈值
def文档比较(self,image1=None,image2=None):
如果不是image1:image1=self.image1
如果不是image2:image2=self.image2
差异=系统模块[“ImageChops”]差异(image1,image2)
返回自映像熵(diffs)
def图像熵(自我、图像):
w、 h=图像大小
a=np.array(image.convert('RGB'))。重塑((w*h,3))
h、 e=np.histogramdd(a,bins=(16,)*3,range=(0256),)*3)
概率=h/np.和(h)
return-np.sum(np.log2(prob[prob>0]))
def OldImage熵(自我、图像):
直方图=图像。直方图()
histlength=总和(直方图)
概率=[浮动(h)/直方图中h的histlength]
return-sum([p*math.log(p,2)表示概率为p,如果p!=0])
类别图像3:
定义初始化(self,image1,image2,阈值=8):
self.image1=image1
如果类型(图像1)=str:
self.image1=sys.modules[“Image”]。打开(self.image1)
self.image2=image2
如果类型(图像2)=str:
self.image2=sys.modules[“Image”]。打开(image2)
self.threshold=阈值
def文档比较(self,image1=None,image2=None):
1.58496250072
5.44792407663
1.58496250072
5.44302784225
1.58496250072
5.59144486002
1.58496250072
5.37568050189
1.58496250072
import math, sys, numpy as np
import PIL.Image, PIL.ImageChops

sys.modules["Image"]      = PIL.Image
sys.modules["ImageChops"] = PIL.ImageChops

from scipy.misc   import imread
from scipy.linalg import norm
from scipy        import sum, average


DEFAULT_DEVICE_WIDTH  = 640
DEFAULT_DEVICE_HEIGHT = 480


class Images:

    def __init__(self, image1, image2, threshold=98, grayscale=True):
        if type(image1) == str:
            self.image1 = sys.modules["Image"].open(image1)
            self.image2 = sys.modules["Image"].open(image2)
        if grayscale:
            self.image1 = self.DoGrayscale(imread(image1).astype(float))
            self.image2 = self.DoGrayscale(imread(image2).astype(float))
        else:
            self.image1    = imread(image1).astype(float)
            self.image2    = imread(image2).astype(float)
        self.threshold = threshold

    def DoComparison(self, image1=None, image2=None):
        if image1: image1 = self.Normalize(image1)
        else:      image1 = self.Normalize(self.image1)
        if image2: image2 = self.Normalize(image2)
        else:      image2 = self.Normalize(self.image2)
        diff = image1 - image2
        m_norm = sum(abs(diff))
        z_norm = norm(diff.ravel(), 0)
        return (m_norm, z_norm)

    def DoGrayscale(self, arr):
        if len(arr.shape) == 3:
            return average(arr, -1)
        else:
            return arr

    def Normalize(self, arr):
        rng = arr.max()-arr.min()
        amin = arr.min()
        return (arr-amin)*255/rng


class Images2:

    def __init__(self, image1, image2, threshold=98, grayscale=True):
        self.image1 = image1
        if type(image1) == str:
            self.image1 = sys.modules["Image"].open(self.image1)
        self.image2 = image2
        if type(image2) == str:
            self.image2 = sys.modules["Image"].open(image2)
        self.threshold = threshold

    def DoComparison(self, image1=None, image2=None):
        if not image1: image1 = self.image1
        if not image2: image2 = self.image2
        diffs = sys.modules["ImageChops"].difference(image1, image2)
        return self.ImageEntropy(diffs)

    def ImageEntropy(self, image):
        w,h = image.size
        a = np.array(image.convert('RGB')).reshape((w*h,3))
        h,e = np.histogramdd(a, bins=(16,)*3, range=((0,256),)*3)
        prob = h/np.sum(h)
        return -np.sum(np.log2(prob[prob>0]))


    def OldImageEntropy(self, image):
        histogram   = image.histogram()
        histlength  = sum(histogram)
        probability = [float(h) / histlength for h in histogram]
        return -sum([p * math.log(p, 2) for p in probability if p != 0])



class Images3:

    def __init__(self, image1, image2, threshold=8):
        self.image1 = image1
        if type(image1) == str:
            self.image1 = sys.modules["Image"].open(self.image1)
        self.image2 = image2
        if type(image2) == str:
            self.image2 = sys.modules["Image"].open(image2)
        self.threshold = threshold

    def DoComparison(self, image1=None, image2=None):
        if not image1: image1 = self.image1
        if not image2: image2 = self.image2
        image = image1
        monoimage1 = image1.convert("P", palette=sys.modules["Image"].ADAPTIVE, colors=2)
        monoimage2 = image2.convert("P", palette=sys.modules["Image"].ADAPTIVE, colors=2)
        imgdata1   = monoimage1.getdata()
        imgdata2   = monoimage2.getdata()

        changed = 0
        i = 0
        acc = 3

        while i < DEFAULT_DEVICE_WIDTH * DEFAULT_DEVICE_HEIGHT:
            now  = imgdata1[i]
            prev = imgdata2[i]
            if now != prev:
                x = (i % DEFAULT_DEVICE_WIDTH)
                y = (i / DEFAULT_DEVICE_HEIGHT)
                try:
                    #if self.view == "normal":
                    image.putpixel((x,y), (0,0,256))
                    #else:
                    #    monoimage.putpixel((x,y), (0,0,256))
                except:
                    pass
                changed += 1
            i += 1
        percchange = float(changed) / float(DEFAULT_DEVICE_WIDTH * DEFAULT_DEVICE_HEIGHT)
        return percchange


if __name__ == "__main__":
    # image1 & image2 MUST be legit paths!
    image1 = "C:\\Path\\To\\Your\\First\\Image.jpg"
    image2 = "C:\\Path\\To\\Your\\Second\\Image.jpg"

    print "Images Result:"
    print Images(image1, image2).DoComparison()

    print "\nImages2 Result:"
    print Images2(image1, image2).DoComparison()

    print "\nImages3 Result:"
    print Images3(image1, image2).DoComparison()
from PIL import Image, ImageChops
import math

def image_entropy(img):
    """calculate the entropy of an image"""
    # this could be made more efficient using numpy
    histogram = img.histogram()
    histogram_length = sum(histogram)
    samples_probability = [float(h) / histogram_length for h in histogram]
    return -sum([p * math.log(p, 2) for p in samples_probability if p != 0])

# testing..

img1 = Image.open('SnowCam_main1.jpg')
img2 = Image.open('SnowCam_main2.jpg')
img3 = Image.open('SnowCam_main3.jpg')

# No Difference
img = ImageChops.difference(img1,img1)
img.save('test_diff1.png')
print image_entropy(img) # 1.58496250072

# Small Difference
img = ImageChops.difference(img1,img2)
img.save('test_diff2.png') 
print image_entropy(img) # 5.76452986917

# Large Difference
img = ImageChops.difference(img1,img3)
img.save('test_diff3.png')
print image_entropy(img) # 8.15698432026
import numpy as np
def image_entropy(img):
    w,h = img.size
    a = np.array(img.convert('RGB')).reshape((w*h,3))
    h,e = np.histogramdd(a, bins=(16,)*3, range=((0,256),)*3)
    prob = h/np.sum(h) # normalize
    prob = prob[prob>0] # remove zeros
    return -np.sum(prob*np.log2(prob))