'**SUMMARY**
findMotion performs an optical flow calculation. This method attempts to find
motion between two subsequent frames of an image. You provide it
with the previous frame image and it returns a feature set of motion
fetures that are vectors in the direction of motion.
**PARAMETERS**
* *previous_frame* - The last frame as an Image.
* *window* - The block size for the algorithm. For the the HS and LK methods
this is the regular sample grid at which we return motion samples.
For the block matching method this is the matching window size.
* *method* - The algorithm to use as a string.
Your choices are:
* \'BM\' - default block matching robust but slow - if you are unsure use this.
* \'LK\' - `Lucas-Kanade method <http://en.wikipedia.org/wiki/Lucas%E2%80%93Kanade_method>`_
* \'HS\' - `Horn-Schunck method <http://en.wikipedia.org/wiki/Horn%E2%80%93Schunck_method>`_
* *aggregate* - If aggregate is true, each of our motion features is the average of
motion around the sample grid defined by window. If aggregate is false
we just return the the value as sampled at the window grid interval. For
block matching this flag is ignored.
**RETURNS**
A featureset of motion objects.
**EXAMPLES**
>>> cam = Camera()
>>> img1 = cam.getImage()
>>> img2 = cam.getImage()
>>> motion = img2.findMotion(img1)
>>> motion.draw()
>>> img2.show()
**SEE ALSO**
:py:class:`Motion`
:py:class:`FeatureSet`'

def findMotion(self, previous_frame, window=11, method='BM', aggregate=True):

    try:
        import cv2
        ver = cv2.__version__
        if (not ver.startswith('$Rev:')):
            if (int(ver.replace('.', '0')) >= 20400):
                FLAG_VER = 1
                if (window > 9):
                    window = 9
        else:
            FLAG_VER = 0
    except:
        FLAG_VER = 0
    if ((self.width != previous_frame.width) or (self.height != previous_frame.height)):
        logger.warning('ImageClass.getMotion:    To    find    motion    the    current    and    previous    frames    must    match')
        return None
    fs = FeatureSet()
    max_mag = 0.0
    if ((method == 'LK') or (method == 'HS')):
        xf = cv.CreateImage((self.width, self.height), cv.IPL_DEPTH_32F, 1)
        yf = cv.CreateImage((self.width, self.height), cv.IPL_DEPTH_32F, 1)
        win = (window, window)
        if (method == 'LK'):
            cv.CalcOpticalFlowLK(self._getGrayscaleBitmap(), previous_frame._getGrayscaleBitmap(), win, xf, yf)
        else:
            cv.CalcOpticalFlowHS(previous_frame._getGrayscaleBitmap(), self._getGrayscaleBitmap(), 0, xf, yf, 1.0, ((cv.CV_TERMCRIT_ITER | cv.CV_TERMCRIT_EPS), 10, 0.01))
        w = math.floor((float(window) / 2.0))
        cx = (((self.width - window) / window) + 1)
        cy = (((self.height - window) / window) + 1)
        vx = 0.0
        vy = 0.0
        for x in range(0, int(cx)):
            for y in range(0, int(cy)):
                xi = ((x * window) + w)
                yi = ((y * window) + w)
                if aggregate:
                    lowx = int((xi - w))
                    highx = int((xi + w))
                    lowy = int((yi - w))
                    highy = int((yi + w))
                    xderp = xf[lowy:highy, lowx:highx]
                    yderp = yf[lowy:highy, lowx:highx]
                    vx = np.average(xderp)
                    vy = np.average(yderp)
                else:
                    vx = xf[(yi, xi)]
                    vy = yf[(yi, xi)]
                mag = ((vx * vx) + (vy * vy))
                if (mag > max_mag):
                    max_mag = mag
                fs.append(Motion(self, xi, yi, vx, vy, window))
    elif (method == 'BM'):
        if (FLAG_VER == 0):
            block = (window, window)
            shift = (int((window * 1.2)), int((window * 1.2)))
            spread = ((window * 2), (window * 2))
            wv = ((self.width - block[0]) / shift[0])
            hv = ((self.height - block[1]) / shift[1])
            xf = cv.CreateMat(hv, wv, cv.CV_32FC1)
            yf = cv.CreateMat(hv, wv, cv.CV_32FC1)
            cv.CalcOpticalFlowBM(previous_frame._getGrayscaleBitmap(), self._getGrayscaleBitmap(), block, shift, spread, 0, xf, yf)
        elif (FLAG_VER == 1):
            block = (window, window)
            shift = (int((window * 0.2)), int((window * 0.2)))
            spread = (window, window)
            wv = ((self.width - block[0]) + shift[0])
            hv = ((self.height - block[1]) + shift[1])
            xf = cv.CreateImage((wv, hv), cv.IPL_DEPTH_32F, 1)
            yf = cv.CreateImage((wv, hv), cv.IPL_DEPTH_32F, 1)
            cv.CalcOpticalFlowBM(previous_frame._getGrayscaleBitmap(), self._getGrayscaleBitmap(), block, shift, spread, 0, xf, yf)
        for x in range(0, int(wv)):
            for y in range(0, int(hv)):
                xi = ((shift[0] * x) + block[0])
                yi = ((shift[1] * y) + block[1])
                vx = xf[(y, x)]
                vy = yf[(y, x)]
                fs.append(Motion(self, xi, yi, vx, vy, window))
                mag = ((vx * vx) + (vy * vy))
                if (mag > max_mag):
                    max_mag = mag
    else:
        logger.warning('ImageClass.findMotion:    I    don\'t    know    what    algorithm    you    want    to    use.    Valid    method    choices    are    Block    Matching    ->    "BM"    Horn-Schunck    ->    "HS"    and    Lucas-Kanade->"LK"    ')
        return None
    max_mag = math.sqrt(max_mag)
    for f in fs:
        f.normalizeTo(max_mag)
    return fs
