Exemplo n.º 1
0
class MotionDetector():
    _hasIgnoredFirstImage = False
    _snapShotter = None
    _isDetecting = False
    _imageAnalyzer = None
    _previousPixelCounts = []
    _previousSquaredDifference = []
    numberOfImagesToAverage = 3
    motionDetectorHandler = None

    # PiCameraSnapShotter callbacks
    def snapShotterFileNameForCapture(self):
        fileName = datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S.%f')[:-3]
        fileName = "%s.bmp" % fileName
        return fileName

    def snapShotterDidCaptureImage(self, snapShotter, imagePath):
        # the first image is ignored, as it is very different form the second
        # one, even when no change in the scene is present. (Maybe the PiCam
        # still has to focus or adjust light settings).
        if not self._hasIgnoredFirstImage:
            self._hasIgnoredFirstImage = True
            os.remove(imagePath)
            return

        if self._imageAnalyzer == None:
            self._imageAnalyzer = ImageAnalyzer(initialImagePath = imagePath)
        else:
            analysisResult = self._imageAnalyzer.compareNextImage(
                imagePath)
            if analysisResult != None:
                (differentPixelCount,
                    totalSquaredDifference,
                    totalNumberOfPixels) = analysisResult
                self.analyzeNewImageResult(
                    differentPixelCount,
                    totalSquaredDifference)

        os.remove(imagePath)

    def analyzeNewImageResult(
        self,
        differentPixelCount,
        totalSquaredDifference):

        self._previousPixelCounts.append(differentPixelCount)
        self._previousSquaredDifference.append(totalSquaredDifference)

        if len(self._previousSquaredDifference) > self.numberOfImagesToAverage:
            self._previousSquaredDifference.pop(0)
            self._previousPixelCounts.pop(0)

        if len(self._previousPixelCounts) == self.numberOfImagesToAverage:
            pixelSum = sum(self._previousSquaredDifference)
            pixelLength = len(self._previousSquaredDifference)
            averagePixelDifference = pixelSum / float(pixelLength)

            differenceSum = sum(self._previousPixelCounts)
            differenceLength = len(self._previousPixelCounts)
            averagePixelCount = differenceSum / float(differenceLength)

            pixels = abs(differentPixelCount - averagePixelCount)
            squaredDelta = None
            if abs(averagePixelDifference) > 0:
                squaredDelta = abs(totalSquaredDifference / averagePixelDifference)

            # these are some of the values that can be tweaked for
            # a better detection experience (maybe a true)
            if squaredDelta > 1.1 and pixels > 10:
                if self.motionDetectorHandler is None:
                    timestamp = datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S.%f')[:-3]
                    print "%s - Motion detected, but there is no handler." %timestamp
                else:
                    self.motionDetectorHandler.motionDetectorDetectedMotion(self)

    def startDetecting(self):
        if self._isDetecting == False:
            self._isDetecting = True
            thread = Thread(target = self._startDetectingOnThread)
            thread.start()
        else:
            print "Already detecting, ignoring call to startDetecting()"

    def _startDetectingOnThread(self):
        if self._snapShotter == None:
            snapShotter = PiCameraSnapshotter(repeats = True, interval = 1.0)
            snapShotter.delegate = self

        snapShotter.startSnapShotting()
        while self._isDetecting == True:
            time.sleep(1)

        snapShotter.stopSnapShotting()

    def stopDetecting(self):
        if self._isDetecting == True:
            self._imageAnalyzer.cancel();
            self._isDetecting = False
        else:
            print "Not detecting, ignoring call to stopDetecting()"