15

I can get frames from my webcam using OpenCV in Python. The camshift example is close to what I want, but I don't want human intervention to define the object. I want to get the center point of the total pixels that have changed over the course of several frame, i.e. the center of the moving object.

msw
  • 42,753
  • 9
  • 87
  • 112
Matt Williamson
  • 39,165
  • 10
  • 64
  • 72
  • http://stackoverflow.com/questions/3374422/how-do-i-track-a-blob-using-opencv-and-python for question context – rlb.usa Jul 30 '10 at 19:52

4 Answers4

33

I've got some working code translated from the C version of code found in the blog post Motion Detection using OpenCV:

#!/usr/bin/env python

import cv

class Target:

    def __init__(self):
        self.capture = cv.CaptureFromCAM(0)
        cv.NamedWindow("Target", 1)

    def run(self):
        # Capture first frame to get size
        frame = cv.QueryFrame(self.capture)
        frame_size = cv.GetSize(frame)
        color_image = cv.CreateImage(cv.GetSize(frame), 8, 3)
        grey_image = cv.CreateImage(cv.GetSize(frame), cv.IPL_DEPTH_8U, 1)
        moving_average = cv.CreateImage(cv.GetSize(frame), cv.IPL_DEPTH_32F, 3)

        first = True

        while True:
            closest_to_left = cv.GetSize(frame)[0]
            closest_to_right = cv.GetSize(frame)[1]

            color_image = cv.QueryFrame(self.capture)

            # Smooth to get rid of false positives
            cv.Smooth(color_image, color_image, cv.CV_GAUSSIAN, 3, 0)

            if first:
                difference = cv.CloneImage(color_image)
                temp = cv.CloneImage(color_image)
                cv.ConvertScale(color_image, moving_average, 1.0, 0.0)
                first = False
            else:
                cv.RunningAvg(color_image, moving_average, 0.020, None)

            # Convert the scale of the moving average.
            cv.ConvertScale(moving_average, temp, 1.0, 0.0)

            # Minus the current frame from the moving average.
            cv.AbsDiff(color_image, temp, difference)

            # Convert the image to grayscale.
            cv.CvtColor(difference, grey_image, cv.CV_RGB2GRAY)

            # Convert the image to black and white.
            cv.Threshold(grey_image, grey_image, 70, 255, cv.CV_THRESH_BINARY)

            # Dilate and erode to get people blobs
            cv.Dilate(grey_image, grey_image, None, 18)
            cv.Erode(grey_image, grey_image, None, 10)

            storage = cv.CreateMemStorage(0)
            contour = cv.FindContours(grey_image, storage, cv.CV_RETR_CCOMP, cv.CV_CHAIN_APPROX_SIMPLE)
            points = []

            while contour:
                bound_rect = cv.BoundingRect(list(contour))
                contour = contour.h_next()

                pt1 = (bound_rect[0], bound_rect[1])
                pt2 = (bound_rect[0] + bound_rect[2], bound_rect[1] + bound_rect[3])
                points.append(pt1)
                points.append(pt2)
                cv.Rectangle(color_image, pt1, pt2, cv.CV_RGB(255,0,0), 1)

            if len(points):
                center_point = reduce(lambda a, b: ((a[0] + b[0]) / 2, (a[1] + b[1]) / 2), points)
                cv.Circle(color_image, center_point, 40, cv.CV_RGB(255, 255, 255), 1)
                cv.Circle(color_image, center_point, 30, cv.CV_RGB(255, 100, 0), 1)
                cv.Circle(color_image, center_point, 20, cv.CV_RGB(255, 255, 255), 1)
                cv.Circle(color_image, center_point, 10, cv.CV_RGB(255, 100, 0), 1)

            cv.ShowImage("Target", color_image)

            # Listen for ESC key
            c = cv.WaitKey(7) % 0x100
            if c == 27:
                break

if __name__=="__main__":
    t = Target()
    t.run()
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Matt Williamson
  • 39,165
  • 10
  • 64
  • 72
  • Thank you for your code. It works, and it can detect all the moving objects. However, it can not tracking the moving object. Is there any better way of tracking moving object? I am thinking to calculate the center of each contour, can compare the position changed between 2 frames, but the hard part is, if there are many contours in a frame, and there are very close, it's hard to tell for one contour, which is next contour in next frame. – Frank Dec 25 '12 at 10:00
  • It's been a while since I used OpenCV, but I recall using a demo included with the source, where you drag a square around an object with the mouse to track. It grabs the selection's color histogram and looks for that. I believe it was this piece of code: https://code.ros.org/trac/opencv/browser/trunk/opencv/samples/python/camshift.py?rev=2136 – Matt Williamson Dec 27 '12 at 22:13
  • Is it possible to use this script and use the color_image as a mjpeg network stream at the same time. I want to be able to monitor the camera on the PC it is connected to and at the same time view the stream from my Android Phone. – PrestonDocks Jun 03 '13 at 22:45
  • I haven't tried it, but a cursory google search turns up stuff like http://ariandy1.wordpress.com/2013/04/07/streaming-opencv-output-through-httpnetwork-with-mjpeg/ – Matt Williamson Jun 04 '13 at 14:53
  • This code doesn't work for OpenCV version 3.2. I tried messing around with it to make it work, but I'm having a lot of trouble with it. Do you maybe have an updated version of this code available which you can share with us? – kramer65 Feb 16 '17 at 19:38
1

See the forum post Motion tracking using OpenCV.

I believe you are capable of reading and translating the source code to Python, right?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
karlphillip
  • 92,053
  • 36
  • 243
  • 426
0
if faces:
    for ((x, y, w, h), n) in faces:
        pt1 = (int(x * image_scale), int(y * image_scale))
        pt2 = (int((x + w) * image_scale), int((y + h) * image_scale))
        ptcx=((pt1[0]+pt2[0])/2)/128
        ptcy=((pt1[1]+pt2[1])/2)/96
        cv.Rectangle(gray, pt1, pt2, cv.RGB(255, 0, 0), 3, 8, 0)
        print ptcx;
        print ptcy;
        b=('S'+str(ptcx)+str(ptcy));

This is the part of the code I tried to get the center of the moving object when tracked using a rectangular boundary.

Zero Piraeus
  • 56,143
  • 27
  • 150
  • 160
0

This following link tracks the moving vehicles as well as counting them. It is based on OpenCV and is written in Python 2.7.
OpenCV and Python

Community
  • 1
  • 1
Rouzbeh
  • 2,141
  • 1
  • 11
  • 19