analitics

Pages

Monday, March 16, 2020

Python 3.5.2 : Detect motion and save images with opencv.

This script is simple to use it with a webcam or to parse a video file.
The main goal of this script is to see the difference in various frames of a video or webcam output.
The first frame of our video file will contain no motion and just background and then is compute the absolute difference.
There is no need to process the large, raw images straight from the video stream and this is the reason I convert the image to grayscale.
Some text is put on the window to show us the status string to indicate it is detection.
With this script I detect cars and peoples from my window, see the screenshot with these files:

Let's see the python script:
import argparse
import datetime
import imutils

import cv2

import time
from time import sleep

def saveJpgImage(frame):
    #process image
    img_name = "opencv_frame_{}.jpg".format(time)
    cv2.imwrite(img_name, frame)

def savePngImage():
    #process image
    img_name = "opencv_frame_{}.png".format(time)
    cv2.imwrite(img_name, frame)

# get argument parse
ap = argparse.ArgumentParser()
ap.add_argument("-v", "--video", help="path to the video file")
ap.add_argument("-s", "--size", type=int, default=480, help="minimum area size , default 480")
args = vars(ap.parse_args())

# if no video use webcam
if args.get("video", None) is None:
    camera = cv2.VideoCapture(0)
    #time.sleep(1.5)

# use video file
else:
    camera = cv2.VideoCapture(args["video"])


# frame from video is none 
first_frame = None

# loop into frames of the video
while True:
    # grab the current frame 
    (grabbed, frame) = camera.read()
    text = "undetected"

    # is no frame grabbed the is end of video 
    if not grabbed:
        break

    # resize the frame 
    frame = imutils.resize(frame, width=640)
    gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
    gray = cv2.GaussianBlur(gray, (21, 21), 0)

    # is first frame is none , make gray 
    if first_frame is None:
        first_frame = gray
        continue


    # compute difference from current frame and first frame 
    frameDelta = cv2.absdiff(first_frame, gray)
    first_frame = gray
    thresh = cv2.threshold(frameDelta, 1, 255, cv2.THRESH_BINARY)[1]

    # dilate the thresholded image to fill in holes
    # then find contours on thresholded image
    thresh = cv2.dilate(thresh, None, iterations=2)
    (cnts, _) = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL,
                                 cv2.CHAIN_APPROX_SIMPLE)

    # loop contours 
    for c in cnts:
        # if the contour is too small, ignore it
        if cv2.contourArea(c) < args["size"]:
            continue

        # compute the bounding box for the contour
        # draw it on the frame,
        # and update the text
        (x, y, w, h) = cv2.boundingRect(c)
        cv2.rectangle(frame, (x, y), (x + w, y + h), (0, 255, 0), 0)
        roi = frame[y:y+h, x:x+w]
        ts = time.time()
        st = datetime.datetime.fromtimestamp(ts).strftime('%d-%m-%Y_%H-%M-%S')
        # if the detection is on sized then save the image 
        if (w > h ) and (y + h) > 50 and (y + h) < 550:
            cv2.imwrite(st+"opencv.jpg", roi)
        # set text to show on gui 
        text = "detected"
    
    # draw the text and timestamp on the frame
    cv2.putText(frame, "Detect: {}".format(text), (10, 20),
                cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 255), 2)
    cv2.putText(frame, datetime.datetime.now().strftime("%A %d %B %Y %I:%M:%S%p"),
                (10, frame.shape[0] - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.35, (0, 0, 255), 1)

    #show frame , thresh and frame_Delta
    cv2.imshow("Security Feed", frame)
    cv2.imshow("Thresh", thresh)
    cv2.imshow("Frame Delta", frameDelta)
    key = cv2.waitKey(1) &  0xFF

    # break from loop with q key 
    if key == ord("q"):
        break

# close camera and windows 
camera.release()
cv2.destroyAllWindows()