pythons opencv running out of frames when using webcam - python

I am trying to set my opencv to make a heat map. I have it working for a set .mp4 file. However when i try to make it work using my webcam on a live feed it doesn't seem to like it. the problem it has is it says that the "index is out of range" fr the following lines of code:
make_video('./frames/', './output.avi')
frame = cv2.imread(os.path.join(image_folder, images[0]))
The .py file is as follows:
import numpy as np
import cv2
import copy
from make_video import make_video
from progress.bar import Bar
def main():
capture = cv2.VideoCapture(0)
background_subtractor = cv2.bgsegm.createBackgroundSubtractorMOG()
length = int(capture.get(cv2.CAP_PROP_FRAME_COUNT))
bar = Bar('Processing Frames', max=length)
print(length)
short = length
first_iteration_indicator = 1
for i in range(0, short):
print(i)
ret, frame = capture.read()
# If first frame
if first_iteration_indicator == 1:
first_frame = copy.deepcopy(frame)
height, width = frame.shape[:2]
accum_image = np.zeros((height, width), np.uint8)
first_iteration_indicator = 0
else:
filter = background_subtractor.apply(frame) # remove the background
cv2.imwrite('./frame.jpg', frame)
cv2.imwrite('./diff-bkgnd-frame.jpg', filter)
threshold = 2
maxValue = 2
ret, th1 = cv2.threshold(filter, threshold, maxValue, cv2.THRESH_BINARY)
# add to the accumulated image
accum_image = cv2.add(accum_image, th1)
cv2.imwrite('./mask.jpg', accum_image)
color_image_video = cv2.applyColorMap(accum_image, cv2.COLORMAP_HOT)
video_frame = cv2.addWeighted(frame, 0.7, color_image_video, 0.7, 0)
name = "./frames/frame%d.jpg" % i
cv2.imwrite(name, video_frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
bar.next()
bar.finish()
make_video('./frames/', './output.avi')
color_image = cv2.applyColorMap(accum_image, cv2.COLORMAP_HOT)
result_overlay = cv2.addWeighted(first_frame, 0.7, color_image, 0.7, 0)
# save the final heatmap
cv2.imwrite('diff-overlay.jpg', result_overlay)
# cleanup
capture.release()
cv2.destroyAllWindows()
if __name__ == '__main__':
main()
in order to set it to the webcam i use capture = cv2.VideoCapture(0) which causes the error above, however if i use a pre-saved .mp4 file like so capture = cv2.VideoCapture('vid.mp4') it works fine.Any ideas?

Problem:
When using your webcam with capture = cv2.VideoCapture(0); the line length = int(capture.get(cv2.CAP_PROP_FRAME_COUNT)) is not helpful. Because, when using a webcam capture.get(cv2.CAP_PROP_FRAME_COUNT) returns -1.0. And that means to say the number of frames does not apply when using webcam. It makes sense when using to read video, since it can find out the number of frames present in the video.
Solution:
I modified the existing code to use the webcam and removed the for loop. I tested this code without make_video. The results were as expected on analyzing them using cv2.imshow (uncomment them to see it for yourself).
import cv2
capture = cv2.VideoCapture(0)
background_subtractor = cv2.bgsegm.createBackgroundSubtractorMOG()
threshold = 100
maxValue = 255
# for counting frames
i = 0
while True:
i = i + 1
ret, frame = capture.read()
if frame is None:
break
fgMask = background_subtractor.apply(frame)
ret, th1 = cv2.threshold(fgMask, threshold, maxValue, cv2.THRESH_BINARY)
blur = cv2.GaussianBlur(th1,(11,11), 9)
heat_map = cv2.applyColorMap(blur, cv2.COLORMAP_HOT)
video_hm = cv2.addWeighted(frame, 0.7, heat_map, 0.7, 0)
name = "./frames/frame%d.jpg" % i
cv2.imwrite(name, video_hm)
#cv2.imshow('Frame', frame)
#cv2.imshow('FG Mask', fgMask)
#cv2.imshow('Video OP', video_hm)
#cv2.imshow('Blur', blur)
keyboard = cv2.waitKey(30)
if keyboard == 'q' or keyboard == 27:
break
capture.release()
make_video('./frames/', './output.avi')
cv2.destroyAllWindows()

Related

OpenCV ret=False, is it reading the video, or not?

I want to detect edges of a video file (640x640 9sn.) and save the result. I followed OpenCV documents and some other examples. Most of the examples that I found was reading from camera.
Here is my code. I checked cap.isOpened(), it returns True but ret does False and frame is NoneType object. What is confusing is that I'm having the gray array which depends the condition if ret == True. How can I get gray matrix if ret = False?
(I installed ffmpeg pip install ffmpeg-python)
(andy.avi was saved in folder but it's broke, empty)
import cv2
import numpy as np
cap = cv2.VideoCapture("...\\video.mp4")
while(cap.isOpened()):
ret, frame = cap.read()
frame_width = int(cap.get(3))
frame_height = int(cap.get(4))
size = (frame_width, frame_height)
result = cv2.VideoWriter('andy.avi',
cv2.VideoWriter_fourcc(*'DIVX'),
30, size)
if ret == True:
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
edges = cv2.Canny(gray, 45, 90)
result.write(edges)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
else:
break
cap.release()
result.release()
cv2.destroyAllWindows()
your code should be changed like this
# importing the module
import cv2
import numpy as np
# reading the vedio
source = cv2.VideoCapture("...\\video.mp4")
# We need to set resolutions.
# so, convert them from float to integer.
frame_width = int(source.get(3))
frame_height = int(source.get(4))
size = (frame_width, frame_height)
result = cv2.VideoWriter('andy.avi',
cv2.VideoWriter_fourcc(*'DIVX'),
30, size, 0)
# running the loop
while True:
# extracting the frames
ret, img = source.read()
# converting to gray-scale
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
edges = cv2.Canny(gray, 45, 90)
# write to gray-scale
result.write(edges)
# displaying the video
cv2.imshow("Live", gray)
# exiting the loop
key = cv2.waitKey(1)
if key == ord("q"):
break
# closing the window
result.release()
source.release()
cv2.destroyAllWindows()
If helpful this for you give 👍

how can i control frames in opencv?

how can i control frames in opencv?
here you insert the url of a video in the internet/local and this streams it to you.but voice and video are not Coordinated.video is faster than voice :/
import cv2
import numpy as np
from ffpyplayer.player import MediaPlayer
def getVideoSource(source, width, height):
cap = cv2.VideoCapture(source)
cap.set(cv2.CAP_PROP_FRAME_WIDTH, width)
cap.set(cv2.CAP_PROP_FRAME_HEIGHT, height)
return cap
def main():
url=input('enter url: ')
sourcePath = url
camera = getVideoSource(sourcePath, 720, 480)
player = MediaPlayer(sourcePath)
while True:
ret, frame = camera.read()
audio_frame, val = player.get_frame()
if (ret == 0):
print("End of video")
break
frame = cv2.resize(frame, (720, 480))
cv2.imshow('Camera', frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
if val != 'eof' and audio_frame is not None:
frame, t = audio_frame
print("Frame:" + str(frame) + " T: " + str(t))
camera.release()
cv2.destroyAllWindows()
if __name__ == "__main__":
main()
A slight modification of the answer by #furas:
player = MediaPlayer(video_path)
while True:
frame, val = player.get_frame()
if val == 'eof':
break # this is the difference
if frame is not None:
image, pts = frame
w, h = image.get_size()
# convert to array width, height
img = np.asarray(image.to_bytearray()[0]).reshape(h,w,3)
# convert RGB to BGR because `cv2` need it to display it
img = cv2.cvtColor(img, cv2.COLOR_RGB2BGR)
time.sleep(val)
cv2.imshow('video', img)
if cv2.waitKey(1) & 0xff == ord('q'):
break
cv2.destroyAllWindows()
player.close_player()
The difference is the explicit break once EOF is reached, which causes the program to terminate. To me, that's expected behavior, so I wanted to post this code in case someone wants that behavior as well.
It seems you can't control when to play audio because it uses SDL to play it in separated thread but get_frame() gives tuple (frame, val) and frame is (image, time_when_to_display_image) and you should use this time_when_to_display_image to control when to display image.
And all this code doesn't need cv2.VideoCapture() to get frame.
I use cv2 only to display it but you can use any GUI to create window to display it.
I use current_time to get next frame without using time.sleep() because video wasn't smooth.
BTW: You can use player.set_size(720, 480) to resize frame.
from ffpyplayer.player import MediaPlayer
import cv2
import numpy as np
import time
filename = 'video.mp4'
player = MediaPlayer(filename)
player.set_size(720, 480) # resize it
#player.set_size(400, 300)
start_time = time.time()
frame_time = start_time + 0
while True:
current_time = time.time()
# check if it is time to get next frame
if current_time >= frame_time:
# get next frame
frame, val = player.get_frame()
if val != 'eof' and frame is not None:
image, pts = frame
w, h = image.get_size()
# convert to array width, height
img = np.asarray(image.to_bytearray()[0]).reshape(h,w,3)
# convert RGB to BGR because `cv2` need it to display it
img = cv2.cvtColor(img, cv2.COLOR_RGB2BGR)
cv2.imshow('video', img)
frame_time = start_time + pts
if cv2.waitKey(1) & 0xff == ord('q'):
break
cv2.destroyAllWindows()
player.close_player()
EDIT: I found that get_frame() gives (frame, val) and this val can be used in time.sleep(val). And probably it should sleep before displaying frame, not after displaying it.
from ffpyplayer.player import MediaPlayer
import cv2
import numpy as np
import time
filename = 'video.mp4'
player = MediaPlayer(filename)
player.set_size(720, 480)
#player.set_size(400, 300)
while True:
frame, val = player.get_frame()
if val != 'eof' and frame is not None:
image, pts = frame
w, h = image.get_size()
# convert to array width, height
img = np.asarray(image.to_bytearray()[0]).reshape(h,w,3)
# convert RGB to BGR because `cv2` need it to display it
img = cv2.cvtColor(img, cv2.COLOR_RGB2BGR)
time.sleep(val)
cv2.imshow('video', img)
if cv2.waitKey(1) & 0xff == ord('q'):
break
cv2.destroyAllWindows()
player.close_player()
EDIT: Code using tkinter to display it.
from ffpyplayer.player import MediaPlayer
import tkinter as tk
from PIL import Image, ImageTk
import time
# -- functions ---
def update_frame():
global photo # solution for BUG in PhotoImage
frame, val = player.get_frame()
if val != 'eof' and frame is not None:
image, pts = frame
w, h = image.get_size()
data = image.to_bytearray()[0]
img = Image.frombytes("RGB", (w,h), bytes(data))
photo = ImageTk.PhotoImage(img)
time.sleep(val)
label['image'] = photo
root.after(1, update_frame) # again after `1ms` without blocking `mainloop()`
# --- main ---
filename = 'video.mp4'
player = MediaPlayer(filename)
player.set_size(720, 480)
#player.set_size(400, 300)
root = tk.Tk()
label = tk.Label(root)
label.pack()
root.bind('q', lambda event:root.destroy())
update_frame()
root.mainloop()
player.close_player()

How to solve Opencv VideoWriter issues with global variables

I'mm writing this piece of python to display a stream of video from my webcam while at the same time record the video - which I've got working, however I've grayscaled the video streaming to my screen and time stamped it - but my recorded video is in colour! I've included the code below - I've tried using some global variables but nothing worked - any help, greatly appreciated
import cv2
import numpy as np
import time, datetime
import os
genericfilename = "recording"
filetime = str(time.time())
extension = '.avi'
filename = genericfilename + filetime +extension
frames_per_second = 100
res = '720p'
print("NEW FILE NAME: " + filename)
# Set resolution for the video capture
def change_res(cap, width, height):
cap.set(3, width)
cap.set(4, height)
# Standard Video Dimensions Sizes
STD_DIMENSIONS = {
"480p": (640, 480),
"720p": (1280, 720),
"1080p": (1920, 1080),
"4k": (3840, 2160),
}
# grab resolution dimensions and set video capture to it.
def get_dims(cap, res='1080p'):
width, height = STD_DIMENSIONS["480p"]
if res in STD_DIMENSIONS:
width,height = STD_DIMENSIONS[res]
## change the current caputre device
## to the resulting resolution
change_res(cap, width, height)
return width, height
# Video Encoding, might require additional installs
VIDEO_TYPE = {
'avi': cv2.VideoWriter_fourcc(*'XVID'),
#'mp4': cv2.VideoWriter_fourcc(*'H264'),
'mp4': cv2.VideoWriter_fourcc(*'XVID'),
}
def get_video_type(filename):
filename, ext = os.path.splitext(filename)
if ext in VIDEO_TYPE:
return VIDEO_TYPE[ext]
return VIDEO_TYPE['avi']
capture = cv2.VideoCapture(0)
out = cv2.VideoWriter(filename, get_video_type(filename), 60,
get_dims(capture, res))
while(True):
ret, frame = capture.read()
out.write(frame)
grayFrame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
font = cv2.FONT_ITALIC = 1
cv2.putText(grayFrame, str(datetime.datetime.now()), (-330, 460), font, 3,
(200, 200, 200), 2, cv2.LINE_AA)
cv2.imshow('combilift output', grayFrame)
# Press Q on keyboard to exit
if cv2.waitKey(1) & 0xFF == ord('q'):
break
if cv2.waitKey(1) & 0xFF == ord('r'):
print(datetime.datetime.now())
capture.release()
out.release()
cv2.destroyAllWindows()
You save the frame to video, then convert frame to gray.
out.write(frame)
grayFrame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
If you want your recorded video to be gray, maybe reverse the order of operations and save grayFrame?
grayFrame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
out.write(grayFrame)
If you want to also save the texts, put the text before writing frame to output.
Lets take a look at ur code
out = cv2.VideoWriter(filename, get_video_type(filename), 60,
.....
while(True):
ret, frame = capture.read()
out.write(frame)
grayFrame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
You first save out then convert color
The correct sequence should be
out = cv2.VideoWriter(filename, get_video_type(filename), 60,
.....
while(True):
ret, frame = capture.read()
grayFrame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
out.write(grayFrame)
I don't have data to test. Just in case you experience some issue with channels. You can use opencv merge(grayFrame,grayFrame,grayFrame) to create a normal 3 channel grey scale image and save to video

How can I zoom my webcam in Open CV Python?

I want my webcam to be zoomed in open cv python and I don't know how. Can anyone help me with my problem?
import cv2
video = cv2.VideoCapture(0)
while True:
check, frame = video.read()
cv2.imshow('Video', frame)
key = cv2.waitKey(1)
if key == 27:
break
video.release()
cv2.destroyAllWindows
You can use this solution. It makes the job -> croping + zoom + array up and array down.
import cv2
def show_webcam(mirror=False):
scale=10
cam = cv2.VideoCapture(0)
while True:
ret_val, image = cam.read()
if mirror:
image = cv2.flip(image, 1)
#get the webcam size
height, width, channels = image.shape
#prepare the crop
centerX,centerY=int(height/2),int(width/2)
radiusX,radiusY= int(scale*height/100),int(scale*width/100)
minX,maxX=centerX-radiusX,centerX+radiusX
minY,maxY=centerY-radiusY,centerY+radiusY
cropped = image[minX:maxX, minY:maxY]
resized_cropped = cv2.resize(cropped, (width, height))
cv2.imshow('my webcam', resized_cropped)
if cv2.waitKey(1) == 27:
break # esc to quit
#add + or - 5 % to zoom
if cv2.waitKey(1) == 0:
scale += 5 # +5
if cv2.waitKey(1) == 1:
scale = 5 # +5
cv2.destroyAllWindows()
def main():
show_webcam(mirror=True)
if __name__ == '__main__':
main()
Zooming is simply increasing image size . Just increase image size by converting frame to image using PIL and then resize function.
Sample code
import tkinter
import cv2
from PIL import Image,ImageTk
root = tkinter.Tk()
root.geometry("1000x500+200+0")
w = 1000
h = 630
capture = tkinter.Canvas(root, bd=2, bg="blue", height=h, width=w)
capture.grid(column = 0, row = 0)
video = None
frame = None
img=None
show=None
begin = False
def start_capture(event):
global begin,frame,img,root,show,capture,video
video = cv2.VideoCapture(0)
begin = True
while begin:
check, frame = video.read()
img = Image.fromarray(frame)
w,h = img.size
img = img.resize((w*2,h*2))
show = ImageTk.PhotoImage(img)
capture.create_image(0,0,anchor=tkinter.NW,image=show)
root.update()
def stop_capture(event):
global video,begin
begin = False
video.release()
start = tkinter.Button(root, text='Start')
start.grid(column = 0, row = 2)
start.bind('<Button-1>', start_capture)
stop = tkinter.Button(root, text='Stop')
stop.grid(column = 1, row = 2)
stop.bind('<Button-1>', stop_capture)
root.mainloop()
I am not sure if this is useful now to add this point. (Hope this helps for all the noobs in opencv at least)
I suffered a lot at this: cropped = image[minX:maxX, minY:maxY] Crop was somehow out of the interested area.
After researching a lot, I found out that the problem was with the syntax.
Actually it should have been : cropped = image[minY:maxY , minX:maxX]
because openCV crop syntax should be like this?..
Anyways, thanks to Amara BOUDIB & JDS for the sample codes!

(cv2,capture) object is not callable

Basically, this code will detect object's motion in the scene. When the motion is detected, a red rectangle frame will track the object's motion. But, I added a new function into the code which is frame differencing. In general it is thresholding. When i run the code it says:"cv2.capture" object is not callable.
import cv2.cv as cv
class Target:
def __init__(self):
self.capture = cv.CaptureFromCAM(0)
cv.NamedWindow("Target", 1)
def run(self):
# Capture first frame to get size
ret, current_frame = self.capture()
previous_frame = current_frame
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:
current_frame_gray = cv2.cvtColor(current_frame,cv2.COLOR_BGR2GRAY)
previous_frame_gray = cv2.cvtColor(previous_frame, cv2.COLOR_BGR2GRAY)
frame_diff = cv2.absdiff(current_frame_gray,previous_frame_gray)
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)
cv.ShowImage("Target", color_image)
cv.ShowImage("frame_diff", frame_diff)
# Listen for ESC key
c = cv.WaitKey(7) % 0x100
if c == 27:
break
if __name__=="__main__":
t = Target()
t.run()
This is the original frame differencing code that I wanted transfer from:
import cv2
cap = cv2.VideoCapture(0)
ret, current_frame = cap.read()
previous_frame = current_frame
while(cap.isOpened()):
current_frame_gray = cv2.cvtColor(current_frame, cv2.COLOR_BGR2GRAY)
previous_frame_gray = cv2.cvtColor(previous_frame, cv2.COLOR_BGR2GRAY)
frame_diff = cv2.absdiff(current_frame_gray,previous_frame_gray)
cv2.imshow('frame diff ',frame_diff)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
previous_frame = current_frame.copy()
ret, current_frame = cap.read()
cap.release()
cv2.destroyAllWindows()
You can't call the capture object, but you can read from it by calling its read method. Changing your frame return code to:
ret, current_frame = self.capture.read()
Should fix this.
Edit:
The two lines:
ret, current_frame = self.capture.read()
previous_frame = current_frame
Will work for VideoCapture but not CaptureFromCAM. You apparently don't need them since you can take a frame by doing:
frame = cv.QueryFrame(self.capture)

Categories