Problem with opencv (cv2) detecting motion in my code - python

I have written a code to detect motion through a webcam but whenever I start the code, it works but it detects the entire full screen instead of objects moving in the screen. I noticed that if I close the camera it seems to remove the detection; Here is the code:
import cv2
first_frame = None
video = cv2.VideoCapture(0)
while True:
check, frame = video.read()
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
gray = cv2.GaussianBlur(gray, (21,21),0)
if first_frame is None:
first_frame=gray
continue
delta_frame = cv2.absdiff(first_frame,gray)
thresh_frame = cv2.threshold(delta_frame, 30, 255, cv2.THRESH_BINARY)[1]
thresh_frame = cv2.dilate(thresh_frame,None, iterations=2)
(cnts,_) = cv2.findContours(thresh_frame.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
for contour in cnts:
if cv2.contourArea(contour) < 4000:
continue
(x,y, w, h)= cv2.boundingRect(contour)
cv2.rectangle(frame, (x, y), (x + w, y + h),(0,225,0),3)
cv2.imshow("Delta Frame",delta_frame)
cv2.imshow("Capturing",gray)
cv2.imshow("Threshold Frame",thresh_frame)
cv2.imshow("Color Frame",frame)
key = cv2.waitKey(5)
if key==ord('q'):
break
video.release()
cv2.destroyAllWindows()
The code should be able to detect only moving object in the screen.

I had similar issue a while back when I started with opencv; the problem with the program is the first frame, the first frame captured a dark screen. The difference detected by cv2.absdiff of the first frame(first_frame) vs the next frames(gray) was big enough that the cv2.findContours was indicated on the whole screen. This may be caused by camera delay
It can be solved by incorporating a slight delay between when the camera load to when the program records the first frame(first_frame) with time.sleep(). Try this:
import cv2, time
first_frame = None
video = cv2.VideoCapture(0)
# the camera has some lag time hence the starting of video.read outside loop and sleep
video.read()
time.sleep(2)
while True:
check, frame = video.read()
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
gray = cv2.GaussianBlur(gray, (21,21),0)
if first_frame is None:
first_frame=gray
continue
delta_frame = cv2.absdiff(first_frame,gray)
thresh_frame = cv2.threshold(delta_frame, 30, 255, cv2.THRESH_BINARY)[1]
thresh_frame = cv2.dilate(thresh_frame,None, iterations=2)
(cnts,_) = cv2.findContours(thresh_frame.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
for contour in cnts:
if cv2.contourArea(contour) < 4000:
continue
(x,y, w, h)= cv2.boundingRect(contour)
cv2.rectangle(frame, (x, y), (x + w, y + h),(0,225,0),3)
cv2.imshow("Delta Frame",delta_frame)
cv2.imshow("Capturing",gray)
cv2.imshow("Threshold Frame",thresh_frame)
cv2.imshow("Color Frame",frame)
key = cv2.waitKey(5)
if key==ord('q'):
break
video.release()
cv2.destroyAllWindows()
time.sleep takes care of the lag time of the camera starting.
Try the code, it worked here

Related

OpenCV Human Body Detection through a webcam - No detections visible

I am trying to detect the human body through OpenCV. The code throws no error. The camera also starts but it is unable to detect anything.
import cv2
classifier = cv2.CascadeClassifier(r'C:\Users\dhruv\Desktop\DataScience\haarcascade_fullbody.xml')
video_captured = cv2.VideoCapture(0)
while (True):
ret, frame = video_captured.read()
frame = cv2.resize(frame,(640,360))
gray_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
# pass the frame to the classifier
persons_detected = classifier.detectMultiScale(gray_frame)
# check if people were detected on the frame
for (x, y, w, h) in persons_detected:
cv2.rectangle(frame, (x,y), (x+w, y+h), (255, 0, 0), 2)
cv2.imshow('Video footage', frame)
if (cv2.waitKey(1) & 0xFF == ord('q')):
break
#cv2.VideoCapture(0).release()
I highly suspect its an indentation error. The camera does start, but your code to draw the bounding boxes of the faces are outside of the loop. Just indent that code. In addition, you'll need to free the camera resource properly or the next time you run the code, the camera will not be able to capture frames properly. I've changed the release call so that it releases the grabbed resource.
import cv2
classifier = cv2.CascadeClassifier(r'C:\Users\dhruv\Desktop\DataScience\haarcascade_fullbody.xml')
video_captured = cv2.VideoCapture(0)
while True:
ret, frame = video_captured.read()
frame = cv2.resize(frame,(640,360))
gray_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
# pass the frame to the classifier
persons_detected = classifier.detectMultiScale(gray_frame)
# check if people were detected on the frame
for (x, y, w, h) in persons_detected:
cv2.rectangle(frame, (x,y), (x+w, y+h), (255, 0, 0), 2)
cv2.imshow('Video footage', frame)
if (cv2.waitKey(1) & 0xFF == ord('q')):
break
video_captured.release() # Changed so that you're releasing the grabbed resource

I need help to fix error when call traker.update with GOTURN tracking

I am learning using GOTURN openCV api to track objects. I am following guide from learnopenCV. After initialize tracker and come into the loop, I got the error when update tracker
ok, bbox = tracker.update(frame)
Traceback (most recent call last):
File "<ipython-input-64-e7c5a34c2f7a>", line 1, in <module>
ok, bbox = tracker.update(frame)
error: OpenCV(4.1.0) C:\projects\opencv-python\opencv\modules\dnn\src\layers\convolution_layer.cpp:282: error: (-2:Unspecified error) Number of input channels should be multiple of 3 but got 1 in function 'cv::dnn::ConvolutionLayerImpl::getMemoryShapes'
I am not sure what channel means. I got the frame from video file and the shape is (row, width, 3). I thought channel is 3 but it does not work. I did try with convert frame to gray scale with shape (row, width), but it still not work either.
Below is my code:
import cv2
import sys
background_path = 'images/images_G1_323/background.png'
background_img = cv2.imread(background_path,cv2.IMREAD_GRAYSCALE)
#cv2.imshow('background image',background_img)
tracker = cv2.TrackerGOTURN_create()
video_path = 'videos/G1_323.avi'
cap = cv2.VideoCapture(video_path)
#fgbg = cv2.createBackgroundSubtractorMOG2()
if cap.isOpened() == False:
print('ERROR FILE NOT FOUND OR WRONG CODEC USED!')
sys.exit()
# Read first frame
ok, frame = cap.read()
ok, frame = cap.read()
ok, frame = cap.read()
frame_gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
if not ok:
print('Cannot read video file')
sys.exit()
#motion = fgbg.apply(frame)
motion = cv2.absdiff(background_img,frame_gray)
_, thresh1 = cv2.threshold(motion, 10, 255, cv2.THRESH_BINARY)
#gray = cv2.cvtColor(thresh1, cv2.COLOR_BGR2GRAY)
blurred = cv2.GaussianBlur(thresh1, (5, 5), 0)
thresh = cv2.threshold(blurred, 30, 255, cv2.THRESH_BINARY)[1]
erosion_size = 10
dilate_size = 14
thresh = cv2.erode(thresh, cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (erosion_size, erosion_size)))
thresh = cv2.dilate(thresh, cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (dilate_size, dilate_size)))
contours, hierarchy = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
c = contours[0]
(x, y, w, h) = cv2.boundingRect(c)
bbox = (x, y, w, h)
# Initialize tracker with first frame and bounding box
ok = tracker.init(frame,bbox)
while (cap.isOpened):
#
#if ret is true than no error with cap.isOpened
ok, frame = cap.read()
frame_gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
if ok==True:
# Start timer
timer = cv2.getTickCount()
# Update tracker
ok, bbox = tracker.update(frame)
# Calculate Frames per second (FPS)
fps = cv2.getTickFrequency() / (cv2.getTickCount() - timer);
# Draw bounding box
if ok:
# Tracking success
p1 = (int(bbox[0]), int(bbox[1]))
p2 = (int(bbox[0] + bbox[2]), int(bbox[1] + bbox[3]))
cv2.rectangle(frame_gray, p1, p2, (255,0,0), 2, 1)
else :
# Tracking failure
cv2.putText(frame_gray, "Tracking failure detected", (100,80), cv2.FONT_HERSHEY_SIMPLEX, 0.75,(0,0,255),2)
# Display tracker type on frame
cv2.putText(frame_gray, "GOTURN Tracker", (100,20), cv2.FONT_HERSHEY_SIMPLEX, 0.75, (50,170,50),2);
# Display FPS on frame
cv2.putText(frame_gray, "FPS : " + str(int(fps)), (100,50), cv2.FONT_HERSHEY_SIMPLEX, 0.75, (50,170,50), 2);
# Display result
cv2.imshow("Tracking", frame_gray)
# Exit if ESC pressed
if cv2.waitKey(100) & 0xFF == ord("q"):
break
else:
break
cap.release()
cv2.destroyAllWindows()
I'm working on the same kind of things, so I hope maybe some of the things I encountered can help you (otherwise I'm sorry for giving a shit answer). I think you should not put it in gray, as it's asking for 3 channels (RGB instead of gray/BW). When you keep the "convert2gray" out, still you're putting: "thresh = cv2.threshold(blurred, 30, 255, cv2.THRESH_BINARY)[1]", which will give you also only 1 channel. Delete the "[1]" at the end and the conversion to gray and maybe it will then work?

Separation of bounding boxes

In this problem we are trying to detect persons in a WEBCAM video in REAL TIME. The code is working fine for 1 person but when more than one person is entering then the code is failing miserably. Here is the code :-
import cv2
import numpy as np
cap = cv2.VideoCapture(0)
kernel = np.ones((5,5), np.uint8)
background = None
while True:
ret,frame = cap.read()
gray = frame.copy()
gray = cv2.cvtColor(gray, cv2.COLOR_BGR2GRAY)
gray = cv2.GaussianBlur(gray, (11,11), 0)
if background is None:
background = gray
continue
delta = cv2.absdiff(background, gray)
thresh = cv2.threshold(delta, 5, 255,
cv2.THRESH_BINARY+cv2.THRESH_OTSU)[1]
thresh = cv2.dilate(thresh, kernel, iterations=2)
_,contours,hierarchy = cv2.findContours(thresh, cv2.RETR_EXTERNAL,
cv2.CHAIN_APPROX_SIMPLE)
if(len(contours)==0):
continue
#areas = [cv2.contourArea(c) for c in contours]
#max_index = np.argmax(areas)
#cnt=contours[max_index]
#(x,y,w,h) = cv2.boundingRect(cnt)
#if(1.0*(w*h)/(640*480)<0.75):
#cv2.rectangle(frame, (x,y), (x+w,y+h), (0,0,255), 3)
#print("Area: ",w*h)
for i in range(len(contours)):
(x,y,w,h) = cv2.boundingRect(contours[i])
if(w*h<=90000):
cv2.rectangle(frame, (x,y), (x+w,y+h), (0,0,255), 5)
#cv2.imshow('thresh', thresh)
cv2.imshow('frame', frame)
if cv2.waitKey(1)==27:
break
cap.release()
cv2.destroyAllWindows()
I think the problem is that the code is not able to separate the different contours of the different persons detected but I may not be the only reason. Can someone help me?

Alpha blending using opencv with a black png on python

I'm trying to create a aplication with opencv that overlaps a glass on me face. However, when the video appears the glasses have a black on the alpha layer. Here is my code:
video_capture = cv2.VideoCapture(0)
anterior = 0
glasses = cv2.imread('Glasses_1.png')
def put_glasses(glasses,fc,x,y,w,h):
face_width = w
face_height = h
glasses_width = int(face_width)
glasses_height = int(face_height*0.32857)
glasses = cv2.resize(glasses,(glasses_width,glasses_height))
for i in range(glasses_height):
for j in range(glasses_width):
for k in range(3):
if glasses[i][j][k]<235:
fc[y+i-int(-0.25*face_height)-1][x+j][k] = glasses[i][j][k]
return fc
while True:
if not video_capture.isOpened():
print('Unable to load camera.')
sleep(5)
pass
ret, frame = video_capture.read()
if ret is True:
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
else:
continue
faces = faceCascade.detectMultiScale(
gray,
scaleFactor=1.1,
minNeighbors=5,
minSize=(40,40)
)
for (x, y, w, h) in faces:
cv2.rectangle(frame, (x, y), (x+w, y+h), (0, 255, 0), 2)
cv2.putText(frame,"Person Detected",(x,y),cv2.FONT_HERSHEY_SIMPLEX,1,(0,0,255),2)
frame = put_glasses(glasses, frame, x, y, w, h)
I will be very grateful if anyone could help.
You read the png in bgr format, not the bgra or unchanged format. Then I don't think your glass image in the program is shape of (h,w,4). You should read with flag cv2.IMREAD_UNCHANGED.
glasses = cv2.imread("xxx.png", cv2.IMREAD_UNCHANGED)
Maybe this link will help. How do I clear a white background in OpenCV with c++?
The bgra worm:
Blending:

Error with global variables are not defined in a thread function on python

I'm working in a project with OCR using a webcam. I defined a capture() function for save the frame that contains minimum 20 contours with areas greater than 60 pixels in lapses of 3 seconds. I need that the main while cycle works all the time. So I'm using a thread to call capture() function. When I run the code the Python Shell returned an error: NameError: global name frame, ln2 are not defined. The 13th commented line solves the error for the variable frame. Does it means that I have to replicate all the code that is inside the while cycle?
I'm using python 2.7 on Windows 7.
Here is the code:
import cv2
import time
import threading
cap = cv2.VideoCapture(0)
def capture():
global frame, ln2
if ln2 > 20:
cv2.imwrite("frame.jpg", frame)
time.sleep(3)
#ret, frame = cap.read() #it solves the error for variable 'frame'
child_t = threading.Thread(target = capture)
child_t.setDaemon(True)
child_t.start()
while(1):
a = []
ret, frame = cap.read()
img1 = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
_, img2 = cv2.threshold(img1, 127, 255, cv2.THRESH_BINARY)
(_, contornos, _) = cv2.findContours(img2, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)
ln = len(contornos)
for i in range (0, ln):
cn = contornos[i]
x, y, w, h = cv2.boundingRect(cn)
area = 2*(w+h)
if area > 60 and area < 1000:
cv2.rectangle(frame, (x,y), (x+w, y+h), (0, 255, 0), 2)
a.append(area)
ln2 = len(a)
print ln2
#here I want to call capture() function
cv2.imshow('Webcam', frame)
if cv2.waitKey(1) & 0xFF == ord('x'):
break
child_t.join()
cap.release()
cv2.destroyAllWindows()
Here you go. Note that I'm using threading.Timer instead of threading.Thread followed by a time.sleep.
Also, You said you need to save the frame that contains minimum 20 contours with areas greater than 60 pixels, but the related if statement in your code doesn't do that. So I've added that as well.
The message NameError: global name frame, ln2 are not defined is because the thread is started even before frame is being read. Same applies to the variable ln2 as well. This is also fixed in the code below. Basically I used the flag writeToFile to overcome this issue.
import threading
import cv2
writeToFile = False
exitTask = False
def threadTask():
global frame
if not exitTask:
threading.Timer(3.0, threadTask).start()
if writeToFile:
cv2.imwrite("Threads.jpg", frame)
print "Wrote to file"
cap = cv2.VideoCapture(0)
threadTask()
while(True):
areasList = []
try:
ret, frame = cap.read()
img1 = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
_, img2 = cv2.threshold(img1, 127, 255, cv2.THRESH_BINARY)
(_, contours, _) = cv2.findContours(img2, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)
nContours = len(contours)
for contour in contours:
x, y, w, h = cv2.boundingRect(contour)
area = 2*(w+h)
#if area > 60 and area < 1000:
if (nContours > 10) and (area > 20):
cv2.rectangle(frame, (x,y), (x+w, y+h), (0, 255, 0), 2)
areasList.append(area)
writeToFile = True
else:
writeToFile = False
#print len(areasList)
cv2.imshow('Webcam', frame)
if cv2.waitKey(1) & 0xFF == ord('x'):
raise KeyboardInterrupt
except KeyboardInterrupt:
exitTask = True
cap.release()
cv2.destroyAllWindows()
exit(0)

Categories