1

I have three IP cameras around my house and I want to capture an image when a motion is detected. I want to run the motion capture algorithm in the same time for all 3 cameras.

I manage to do the job for one camera - Open the stream + motion detection algorithm + store image in case of detection :

import cv2


cap3 = cv2.VideoCapture('http://X.X.X.X:XXXX/stream.mjpg')


ret3, frame31 = cap3.read()
ret3, frame32 = cap3.read()

while (True):
    diff3 = cv2.absdiff(frame31, frame32)
    gray3 = cv2.cvtColor(diff3, cv2.COLOR_BGR2GRAY)
    blur3 = cv2.GaussianBlur(gray3, (5, 5), 0)
    _, tresh3 = cv2.threshold(blur3, 30, 255, cv2.THRESH_BINARY)
    dilated3 = cv2.dilate(tresh3, None, iterations=3)
    contours3, _ = cv2.findContours(dilated3, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)

    for contour in contours3:
        (x, y, w, h) = cv2.boundingRect(contour)
        if cv2.contourArea(contour) < 800:
            continue
        cv2.rectangle(frame31, (x, y), (x + w, y + h), (0, 255, 0), 2)
        cv2.putText(frame31, "Status: {}".format('Movement'), (10, 20), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 255), 3)
        t = time.localtime()
        filename = "RASP" + str(t[0]) + str(t[1]) + str(t[2]) + "_" + str(t[3]) + str(t[4]) + str(t[5]) + ".jpg"
        cv2.imwrite(filename, frame31)

    frame31 = frame32
    ret3, frame32 = cap3.read()

    if cv2.waitKey(1) & 0xFF == ord('q'):
        break

cap3.release()
cv2.destroyAllWindows()

The problem I have is when I try to do the same job in parallel for the three cameras. What I do is duplicating the same process in the while loop for the three cameras and when I do so, it starts running for a few seconds and then I get this error :

Traceback (most recent call last):
  File "C:/Users/Guillaume/PycharmProjects/IPCAM/IPCAM2.py", line 54, in <module>
    gray2 = cv2.cvtColor(diff2, cv2.COLOR_BGR2GRAY)
cv2.error: OpenCV(4.2.0) C:\projects\opencv-python\opencv\modules\imgproc\src\color.cpp:182: error: (-215:Assertion failed) !_src.empty() in function 'cv::cvtColor'

The code I run in below :

import cv2
import numpy as np
from datetime import datetime
import time

cap2 = cv2.VideoCapture('rtsp://')  # IPCAM2
cap = cv2.VideoCapture('rtsp://')  # IPCAM1
cap3 = cv2.VideoCapture('http://')  # RASP

def rescale_frame(frame, percent=75):
    width = int(frame.shape[1] * percent / 100)
    height = int(frame.shape[0] * percent / 100)
    dim = (width, height)
    return cv2.resize(frame, dim, interpolation=cv2.INTER_AREA)

while (True):
    ret1, frame11 = cap.read()
    ret1, frame12 = cap.read()

    ret2, frame21 = cap2.read()
    ret2, frame22 = cap2.read()

    ret3, frame31 = cap3.read()
    ret3, frame32 = cap3.read()

    diff1 = cv2.absdiff(frame11, frame12)
    gray1 = cv2.cvtColor(diff1, cv2.COLOR_BGR2GRAY)
    blur1 = cv2.GaussianBlur(gray1, (5, 5), 0)
    _, tresh1 = cv2.threshold(blur1, 40, 255, cv2.THRESH_BINARY)
    dilated1 = cv2.dilate(tresh1, None, iterations=3)
    contours1, _ = cv2.findContours(dilated1, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)

    for contour in contours1:
        (x, y, w, h) = cv2.boundingRect(contour)
        if cv2.contourArea(contour) < 1000:
            continue
        cv2.rectangle(frame11, (x, y), (x + w, y + h), (0, 255, 0), 2)
        cv2.putText(frame11, "Status: {}".format('Movement'), (10, 20), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 255), 3)
        t = time.localtime()
        filename = str(t[0]) + str(t[1]) + str(t[2]) + "_" + str(t[3]) + str(t[4]) + str(t[5]) + ".jpg"
        cv2.imwrite(filename, frame11)

    # cv2.line(frame, (0, 300), (200, 200), (0, 255, 0), 5)
    resizedframe11 = rescale_frame(frame11, percent=75)

    cv2.imshow('frame', resizedframe11)

    frame11 = frame12
    ret1, frame12 = cap.read()

    diff2 = cv2.absdiff(frame21, frame22)
    gray2 = cv2.cvtColor(diff2, cv2.COLOR_BGR2GRAY)
    blur2 = cv2.GaussianBlur(gray2, (5, 5), 0)
    _, tresh2 = cv2.threshold(blur2, 40, 255, cv2.THRESH_BINARY)
    dilated2 = cv2.dilate(tresh2, None, iterations=3)
    contours2, _ = cv2.findContours(dilated2, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)

    for contour in contours2:
        (x, y, w, h) = cv2.boundingRect(contour)
        if cv2.contourArea(contour) < 1000:
            continue
        cv2.rectangle(frame21, (x, y), (x + w, y + h), (0, 255, 0), 2)
        cv2.putText(frame21, "Status: {}".format('Movement'), (10, 20), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 255), 3)
        t = time.localtime()
        filename = str(t[0]) + str(t[1]) + str(t[2]) + "_" + str(t[3]) + str(t[4]) + str(t[5]) + ".jpg"
        cv2.imwrite(filename, frame21)
    resizedframe21 = rescale_frame(frame21, percent=75)

    cv2.imshow('frame2', resizedframe21)

    frame21 = frame22
    ret2, frame22 = cap2.read()

    diff3 = cv2.absdiff(frame31, frame32)
    gray3 = cv2.cvtColor(diff3, cv2.COLOR_BGR2GRAY)
    blur3 = cv2.GaussianBlur(gray3, (5, 5), 0)
    _, tresh3 = cv2.threshold(blur3, 40, 255, cv2.THRESH_BINARY)
    dilated3 = cv2.dilate(tresh3, None, iterations=3)
    contours3, _ = cv2.findContours(dilated3, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)

    for contour in contours3:
        (x, y, w, h) = cv2.boundingRect(contour)
        if cv2.contourArea(contour) < 800:
            continue
        cv2.rectangle(frame31, (x, y), (x + w, y + h), (0, 255, 0), 2)
        cv2.putText(frame31, "Status: {}".format('Movement'), (10, 20), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 255), 3)
        t = time.localtime()
        filename = "RASP" + str(t[0]) + str(t[1]) + str(t[2]) + "_" + str(t[3]) + str(t[4]) + str(t[5]) + ".jpg"
        cv2.imwrite(filename, frame31)
    resizedframe31 = rescale_frame(frame31, percent=75)

    cv2.imshow('frame3', resizedframe31)

    frame31 = frame32
    ret3, frame32 = cap3.read()

    if cv2.waitKey(1) & 0xFF == ord('q'):
        break
cap.release()
cv2.destroyAllWindows()
Flyghost
  • 33
  • 4
  • Why dont you create threads and process each camera with separate thread. It will be time saving – Karthik Sep 06 '20 at 03:51
  • Thanks Karthik. I will have a look at it. I do not know this lib. Do not hesitate to share further details on how to process this with multiple threads. – Flyghost Sep 06 '20 at 06:58
  • Please check this link https://stackoverflow.com/a/46865932/12870513 – Karthik Sep 06 '20 at 07:02

1 Answers1

0

Thanks Kartik and thekangaroo for your answers. I managed to run my three cameras at the same time using threads. I am just opening them and showing a resized stream. There is another issue as one cameras, and then a second, stops after a random time between 5 to 20 seconds. The stream stops and then the windows closes without any messages. It seems to me that it is due to lagging getting the image from the cameras... any ideas to avoid that with openCV ?

Thanks again for your helpful answers.

Below is the code I use :

import cv2
import threading
import time

class camThread(threading.Thread):
    def __init__(self, previewName, camID):
        threading.Thread.__init__(self)
        self.previewName = previewName
        self.camID = camID
    def run(self):
        print("Starting " + self.previewName)
        camPreview(self.previewName, self.camID)

def rescale_frame(frame, percent=75):
    width = int(frame.shape[1] * percent / 100)
    height = int(frame.shape[0] * percent / 100)
    dim = (width, height)
    return cv2.resize(frame, dim, interpolation=cv2.INTER_AREA)

def camPreview(previewName, camID):
    cv2.namedWindow(previewName)
    cam = cv2.VideoCapture(camID)
    if cam.isOpened():  # try to get the first frame
        rval, frame = cam.read()
    else:
        time.sleep(10)
        rval, frame = cam.read()

    percent = 50
    width = int(frame.shape[1] * percent / 100)
    height = int(frame.shape[0] * percent / 100)
    dim = (width, height)

    while rval:
        # cv2.imshow(previewName, frame)
        cv2.imshow(previewName, cv2.resize(frame, dim, interpolation=cv2.INTER_AREA))
        time.sleep(0.5)
        rval, frame = cam.read()
        key = cv2.waitKey(20)
        print(previewName + str(cam.isOpened()))

# Create two threads as follows
thread1 = camThread("CLIO", 'rtsp://xxxx')
thread2 = camThread("JARDIN", 'rtsp://xxxx')
thread3 = camThread("RASPCAM", 'http://xxxx')

thread1.start()
thread2.start()
thread3.start()
Flyghost
  • 33
  • 4